Vision_数据结构_线段树
来源:互联网 发布:科尔沃折叠刀淘宝 编辑:程序博客网 时间:2024/06/10 07:39
///定义:
/*
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,
每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在
若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实
际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。
*/
/*
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,
每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在
若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,实
际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。
*/
///代码:
/***name:一维线段树**function:一维线段树的最值、区间和,区间更新*/#include <bits/stdc++.h>#define MAXN 100010#define inf 0x3f3f3f3fusing namespace std;struct node{ int l,r;//区间[l,r] int add;//区间的延时标记 int sum;//区间和 int mx; //区间最大值 int mn; //区间最小值}tree[MAXN<<2];//一定要开到4倍多的空间void pushup(int index){ tree[index].sum = tree[index<<1].sum+tree[index<<1|1].sum; tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx); tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn);}void pushdown(int index){ //说明该区间之前更新过 //要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新 if(tree[index].add > 0){ //替换原来的值 tree[index<<1].sum += (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add; tree[index<<1|1].sum +=(tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add; tree[index<<1].mx += tree[index].add; tree[index<<1|1].mx += tree[index].add; tree[index<<1].mn += tree[index].add; tree[index<<1|1].mn += tree[index].add; tree[index<<1].add += tree[index].add; tree[index<<1|1].add += tree[index].add; tree[index].add = 0; }}void build(int l,int r,int index){ tree[index].l = l; tree[index].r = r; tree[index].add = 0;//刚开始一定要清0 if(l == r){ scanf("%d",&tree[index].sum); tree[index].mn = tree[index].mx = tree[index].sum; return ; } int mid = (l+r)>>1; build(l,mid,index<<1); build(mid+1,r,index<<1|1); pushup(index);}void updata(int l,int r,int index,int val){ if(l <= tree[index].l && r >= tree[index].r){ /*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1 个数,所以区间和 以及 最值为: */ /*tree[index].sum = (tree[index].r-tree[index].l+1)*val; tree[index].mn = val; tree[index].mx = val; tree[index].add = val;//延时标记*/ //在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1 //个数,所以区间和 以及 最值为: tree[index].sum += (tree[index].r-tree[index].l+1)*val; tree[index].mn += val; tree[index].mx += val; tree[index].add += val;//延时标记 return ; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; if(l <= mid){ updata(l,r,index<<1,val); } if(r > mid){ updata(l,r,index<<1|1,val); } pushup(index);}int query(int l,int r,int index){ if(l <= tree[index].l && r >= tree[index].r){ //return tree[index].sum; return tree[index].mx; //return tree[index].mn; } pushdown(index); int mid = (tree[index].l+tree[index].r)>>1; int ans = 0; int Max = 0; int Min = inf; if(l <= mid){ ans += query(l,r,index<<1); Max = max(query(l,r,index<<1),Max); Min = min(query(l,r,index<<1),Min); } if(r > mid){ ans += query(l,r,index<<1|1); Max = max(query(l,r,index<<1|1),Max); Min = min(query(l,r,index<<1|1),Min); } //return ans; return Max; //return Min;}int main(){ int n,m,q,x,y,z; while(~scanf("%d%d",&n,&m)){ build(1,n,1); while(m--){ scanf("%d",&q); if(q == 1){ cout<<"查询:(x,y)"<<endl; scanf("%d %d",&x,&y); cout<<query(x,y,1)<<endl; } else{ cout<<"更新(x,y)为z:"<<endl; scanf("%d %d %d",&x,&y,&z); updata(x,y,1,z); for(int i = 1; i <= n; ++i){ printf("a[%d] = %d\n",i,query(i,i,1)); } } } } return 0;}
/***name:一维线段树**function:一维线段树的区间翻转**题意:给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列。用线段树维护区间更改。线段树的叶子节点存每个位置是原序列中的第几号元素。然后维护当前点的编号和每个点的左右儿子的序号,反转区间时,交换左右儿子即可,不过要注意,每次打标记的时候,不能直接把delta置1(防止覆盖原标记),用异或取反*////(注意,这样做是有BUG的,只有在交换区间正好是线段树中的整区间才行。#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int tree[6000010][3],delta[6000010];int n,m,a[150010],num[150010];inline void swap(int now){ int t; t=tree[now][1]; tree[now][1]=tree[now][2]; tree[now][2]=t;}inline void updata(int now){ tree[now][0]=0; tree[now][1]=(now<<1); tree[now][2]=(now<<1)|1;}inline void pushdown(int now){ if(delta[now]) { swap(now<<1); swap(now<<1|1); delta[now<<1]^=1; delta[now<<1|1]^=1; delta[now]=0; }}void build(int now,int l,int r){ if(l==r) { tree[now][0]=l; return; } int mid=(l+r)>>1; build((now<<1),l,mid); build((now<<1)|1,mid+1,r); updata(now);}void change(int now,int l,int r,int al,int ar){ if(al<=l&&r<=ar) { swap(now); delta[now]^=1; return; } int mid=(l+r)>>1; pushdown(now); if(al<=mid) change(tree[now][1],l,mid,al,ar); if(ar>mid) change(tree[now][2],mid+1,r,al,ar);}int ask(int now,int l,int r,int al,int ar){ if(al<=l&&r<=ar) return tree[now][0]; int mid=(l+r)>>1; pushdown(now); if(al<=mid) return ask(tree[now][1],l,mid,al,ar); if(ar>mid) return ask(tree[now][2],mid+1,r,al,ar);}int main(){ int i,j; scanf("%d",&n); for(i=1; i<=n; ++i) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&m); for(i=1; i<=m; ++i) { int x,y; scanf("%d%d",&x,&y); change(1,1,n,x,y); } for(j=1; j<=n; ++j) num[j]=ask(1,1,n,j,j); for(j=1; j<=n; ++j) printf("%d ",a[num[j]]); return 0;}
/***name:二维线段树**function:二维线段树区间翻转**题意:有一个矩阵,初始全是0,然后对区间左上角(x1,y1)-右下角(y1,y2)翻转0变成1,1变成0,然后查询点(x,y)的值*/#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>using namespace std;bool a[1005<<2][1005<<2];///二维线段树int n;void upy(int root,int rt,int l,int r,int y1,int y2){ if(y1<=l&&r<=y2) { a[root][rt]=!a[root][rt];///找到合适的区间进行翻转 return ; } int mid=(l+r)>>1; if(y1<=mid)upy(root,rt<<1,l,mid,y1,y2);///按y更新 if(y2>mid) upy(root,rt<<1|1,mid+1,r,y1,y2);}void upx(int rt,int l,int r,int x1,int x2,int y1,int y2){ if(x1<=l&&r<=x2)///先找出一维x { upy(rt,1,1,n,y1,y2);///在rt这个节点上在建y的线段树 return ; } int mid=(l+r)>>1; if(x1<=mid)upx(rt<<1,l,mid,x1,x2,y1,y2);///按x更新 if(x2>mid) upx(rt<<1|1,mid+1,r,x1,x2,y1,y2);}long long sum;void qy(int root,int rt,int l,int r,int y){ if(a[root][rt])sum++;///在x的root和y的rt这个区间上, ///如果是1就++,因为初始值为0,看翻转的次数 if(l==r)return ; int mid=(l+r)>>1;///结束条件 if(y<=mid)qy(root,rt<<1,l,mid,y);///根据y查找 if(y>mid)qy(root,rt<<1|1,mid+1,r,y);}void qx(int rt,int l,int r,int x,int y){ qy(rt,1,1,n,y);///在rt这个点上查询y if(l==r)return ;///递归结束条件 int mid=(l+r)>>1; if(x<=mid)qx(rt<<1,l,mid,x,y);///查找x的位置 if(x>mid)qx(rt<<1|1,mid+1,r,x,y);}int main(){ int t; cin>>t; while(t--) { int T; char ch[5]; int x,y,x1,x2,y1,y2; cin>>n>>T; memset(a,0,sizeof(a)); while(T--) { scanf("%s",ch); if(ch[0]=='C') { scanf("%d%d%d%d",&x1,&y1,&x2,&y2);///输入更新的区间点 upx(1,1,n,x1,x2,y1,y2);///更新线段树 } else { scanf("%d%d",&x,&y); sum=0; qx(1,1,n,x,y);///在线段树中查询 if(sum%2)printf("1\n");///看(x,y)的所有父节点一共翻转了几次 else printf("0\n"); } } printf("\n"); } return 0;}
/***name:二维线段树求最大值和最小值**来源:HDU4819*/# include<cstdio># include<cstring># include<algorithm>using namespace std;# define lson l,m,rt<<1# define rson m+1,r,rt<<1|1# define MAXN 805int xL,xR,yL,yR,val;int maxv,minv;int Max[MAXN<<2][MAXN<<2],Min[MAXN<<2][MAXN<<2];int N,mat[MAXN][MAXN];void PushUp(int xrt,int rt){ Max[xrt][rt]=max(Max[xrt][rt<<1],Max[xrt][rt<<1|1]); Min[xrt][rt]=min(Min[xrt][rt<<1],Min[xrt][rt<<1|1]);}void BuildY(int xrt,int x,int l,int r,int rt){ int m; if(l==r) { if(x!=-1) Max[xrt][rt]=Min[xrt][rt]=mat[x][l]; else { Max[xrt][rt]=max(Max[xrt<<1][rt],Max[xrt<<1|1][rt]); Min[xrt][rt]=min(Min[xrt<<1][rt],Min[xrt<<1|1][rt]); } return; } m=(l+r)>>1; BuildY(xrt,x,lson); BuildY(xrt,x,rson); PushUp(xrt,rt);}void BuildX(int l,int r,int rt){ int m; if(l==r) { BuildY(rt,l,1,N,1); return; } m=(l+r)>>1; BuildX(lson); BuildX(rson); BuildY(rt,-1,1,N,1);}void UpdateY(int xrt,int x,int l,int r,int rt){ int m; if(l==r) { if(x!=-1) Max[xrt][rt]=Min[xrt][rt]=val; else { Max[xrt][rt]=max(Max[xrt<<1][rt],Max[xrt<<1|1][rt]); Min[xrt][rt]=min(Min[xrt<<1][rt],Min[xrt<<1|1][rt]); } return; } m=(l+r)>>1; if(yL<=m) UpdateY(xrt,x,lson); else UpdateY(xrt,x,rson); PushUp(xrt,rt);}void UpdateX(int l,int r,int rt){ int m; if(l==r) { UpdateY(rt,l,1,N,1); return; } m=(l+r)>>1; if(xL<=m) UpdateX(lson); else UpdateX(rson); UpdateY(rt,-1,1,N,1);}void QueryY(int xrt,int l,int r,int rt){ int m; if(yL<=l&&yR>=r) { minv=min(minv,Min[xrt][rt]); maxv=max(maxv,Max[xrt][rt]); return; } m=(l+r)>>1; if(yL<=m) QueryY(xrt,lson); if(yR>m) QueryY(xrt, rson);}void QueryX(int l,int r,int rt){ int m; if(xL<=l&&xR>=r) { QueryY(rt,1,N,1); return; } m=(l+r)>>1; if(xL<=m) QueryX(lson); if(xR>m) QueryX(rson);}int main(){ //freopen("in.txt","r",stdin); int i,j,q,cas,T,x,y,l; char op[5]; scanf("%d",&T); for(cas=1;cas<=T;cas++) { scanf("%d",&N); for(i=1;i<=N;i++) for(j=1;j<=N;j++) scanf("%d",&mat[i][j]); BuildX(1,N,1); scanf("%d",&q); printf("Case #%d:\n",cas); while(q--) { scanf("%d%d%d",&x,&y,&l); l=(l+1)/2; xL=max(1,x-l+1),xR=min(N,x+l-1); yL=max(1,y-l+1),yR=min(N,y+l-1); minv=1<<30,maxv=-(1<<30); QueryX(1,N,1); val=(maxv+minv)/2; xL=x,yL=y; printf("%d\n",val); UpdateX(1,N,1); } } return 0;}
/***name:二维线段树**function:二维线段树求区间和**题意:一个矩阵,初始化为0,两种操作:1、将某点增加val2、查询一个子矩阵的和**思路:二维线段树,单点更新,区间求和,记得pushup.*/#include<stdio.h>#include<string.h>#include<stdlib.h>#define N 1050#define lson rt<<1,l,mid#define rson rt<<1|1,mid+1,rint sum[N*3][N*3];int n;void SubBuild(int rt,int l,int r,int t){ sum[t][rt] = 0; if(l!=r) { int mid = (l + r) >> 1; SubBuild(lson,t); SubBuild(rson,t); }}void Build(int rt,int l,int r){ SubBuild(1,1,n,rt); if(l!=r) { int mid = (l + r) >> 1; Build(lson); Build(rson); }}void SubUpdate(int rt,int l,int r,int y,int val,int t){ if(l == r) sum[t][rt] += val; else { int mid = (l + r) >> 1; if(y <= mid) SubUpdate(lson,y,val,t); else SubUpdate(rson,y,val,t); sum[t][rt] = sum[t][rt<<1] + sum[t][rt<<1|1]; }}void Update(int rt,int l,int r,int x,int y,int val){ SubUpdate(1,1,n,y,val,rt); if(l!=r) { int mid = (l + r) >> 1; if(x <= mid) Update(lson,x,y,val); else Update(rson,x,y,val); }}__int64 SubQuery(int rt,int l,int r,int LY,int RY,int t){ if(LY <= l && RY >= r) return sum[t][rt]; int mid = (l + r) >> 1; __int64 ans = 0; if(LY <= mid) ans += SubQuery(lson,LY,RY,t); if(RY > mid ) ans += SubQuery(rson,LY,RY,t); return ans;}__int64 Query(int rt,int l,int r,int LX,int RX,int LY,int RY){ if(LX <= l && RX >= r) { return SubQuery(1,1,n,LY,RY,rt); } int mid = (l + r) >> 1; __int64 ans = 0; if(LX <= mid) ans += Query(lson,LX,RX,LY,RY); if(RX > mid ) ans += Query(rson,LX,RX,LY,RY); return ans;}int main(){ int op; int a,b,c,d; while(scanf("%d %d",&op,&n)!=EOF) { ++n; Build(1,1,n); while(scanf("%d",&op)) { if(op == 3) break; if(op == 1) { scanf("%d %d %d",&a,&b,&c); ++a,++b; Update(1,1,n,a,b,c); } else { scanf("%d %d %d %d",&a,&b,&c,&d); ++a,++b,++c,++d; printf("%I64d\n",Query(1,1,n,a,c,b,d)); } } } return 0;}
阅读全文
0 0
- Vision_数据结构_线段树
- Vision_数据结构_舞蹈连
- Vision_数据结构_拓扑排序
- Vision_数据结构_并查集
- Vision_数据结构_RMQ
- 数据结构_线段树_基础模板
- Vision_字符串_后缀数组
- 线段_线段树
- 线段_线段树
- 数据结构_线段树_例题_ I Hate It(HDU 1754)
- Vision_字符串_最小(大)表示法
- Vision_字符串_字符串哈希(BKDR Hash)
- 线段树_总结
- 线段树_模板
- 模板_线段树
- 箱子_线段树
- 箱子_线段树
- 线段树_初步
- Deprecated</b>: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a
- SQL语句中表的基本操作
- 电脑中的声音
- 【LeetCode】C# 106、Construct Binary Tree from Inorder and Postorder Traversal
- 直接选择排序
- Vision_数据结构_线段树
- python切片
- URI中 ? # & 的作用
- xadmin下设置“use_bootswatch = True”无效的原因
- TP框架中的M,D,C,A,I,S方法
- 关于a ++ 与++ a的问题
- 【Leetcode-Easy-155】 Min Stack
- SPI Flash Rom W25Q16 ----基于STC15
- java 覆盖写入