单点更新模板(以区间求和为例)

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=100000; //题目所给最大区间 9 struct node{ 10 int sum; //记录附加信息 11 }arr[maxn*4]; //节点长度开最大区间的四倍 12 13 void pushup(int rt) 14 { 15 arr[rt].sum=arr[rt*2].sum+arr[rt*2+1].sum; 16 } 17 18 void build(int l,int r,int rt) 19 { 20 if ( l==r ) { 21 scanf("%d",&arr[rt].sum); 22 return; 23 } 24 int m=(l+r)/2; 25 build(lson); 26 build(rson); 27 pushup(rt); 28 } 29 30 void update(int p,int add,int l,int r,int rt) 31 { 32 if ( l==r ) { 33 arr[rt].sum+=add; 34 return; 35 } 36 int m=(l+r)/2; 37 if ( p<=m ) update(p,add,lson); 38 else update(p,add,rson); 39 pushup(rt); 40 } 41 42 int query(int L,int R,int l,int r,int rt) 43 { 44 if ( L<=l && r<=R ) return arr[rt].sum; 45 int m=(l+r)/2; 46 int ret=0; 47 if ( L<=m ) ret+=query(L,R,lson); //注意不是左右区间不是if和else的关系,而是并列的关系(拆分区间) 48 if ( R>m ) ret+=query(L,R,rson); 49 return ret; 50 } 51 52 int main() 53 { 54 int n; 55 while ( scanf("%d",&n)!=EOF ) { 56 build(root); 57 //操作 58 } 59 return 0; 60 }
成段更新模板(以区间求和为例)

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 typedef long long ll; 9 const int maxn=100005; 10 struct node{ 11 ll sum; 12 }arr[maxn*4]; 13 ll add[maxn*4]; //延迟标记 14 15 void pushup(int rt) 16 { 17 arr[rt].sum=arr[rt*2].sum+arr[rt*2+1].sum; 18 } 19 20 void pushdown(int rt,int m) 21 { 22 if ( add[rt] ) { 23 add[rt*2]+=add[rt]; 24 add[rt*2+1]+=add[rt]; 25 arr[rt*2].sum+=add[rt]*(m-m/2); 26 arr[rt*2+1].sum+=add[rt]*(m/2); 27 add[rt]=0; 28 } 29 } 30 31 void build(int l,int r,int rt) 32 { 33 add[rt]=0; 34 if ( l==r ) { 35 scanf("%lld",&arr[rt].sum); 36 return; 37 } 38 int m=(l+r)/2; 39 build(lson); 40 build(rson); 41 pushup(rt); 42 } 43 44 void update(int L,int R,int c,int l,int r,int rt) 45 { 46 if ( L<=l && r<=R ) { 47 add[rt]+=c; 48 arr[rt].sum+=(ll)c*(r-l+1); 49 return; 50 } 51 pushdown(rt,r-l+1); 52 int m=(l+r)/2; 53 if ( L<=m ) update(L,R,c,lson); 54 if ( m<R ) update(L,R,c,rson); 55 pushup(rt); 56 } 57 58 ll query(int L,int R,int l,int r,int rt) 59 { 60 if ( L<=l && r<=R ) return arr[rt].sum; 61 pushdown(rt,r-l+1); 62 int m=(l+r)/2; 63 ll ret=0; 64 if ( L<=m ) ret+=query(L,R,lson); 65 if ( m<R ) ret+=query(L,R,rson); 66 return ret; 67 }
练习题
区间最值和区间求和
1.(HDOJ1166)http://acm.hdu.edu.cn/showproblem.php?pid=1166
单点更新模板题

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=50005; //题目所给最大区间 9 struct node{ 10 int sum; 11 }arr[maxn*4]; //节点长度开最大区间的四倍 12 13 void pushup(int rt) 14 { 15 arr[rt].sum=arr[rt*2].sum+arr[rt*2+1].sum; 16 } 17 18 void build(int l,int r,int rt) 19 { 20 if ( l==r ) { 21 scanf("%d",&arr[rt].sum); 22 return; 23 } 24 int m=(l+r)/2; 25 build(lson); 26 build(rson); 27 pushup(rt); 28 } 29 30 void update(int p,int add,int l,int r,int rt) 31 { 32 if ( l==r ) { 33 arr[rt].sum+=add; 34 return; 35 } 36 int m=(l+r)/2; 37 if ( p<=m ) update(p,add,lson); 38 else update(p,add,rson); 39 pushup(rt); 40 } 41 42 int query(int L,int R,int l,int r,int rt) 43 { 44 if ( L<=l && r<=R ) return arr[rt].sum; 45 int m=(l+r)/2; 46 int ret=0; 47 if ( L<=m ) ret+=query(L,R,lson); 48 if ( R>m ) ret+=query(L,R,rson); 49 return ret; 50 } 51 52 int main() 53 { 54 int n,T,i,j,k,ans,h,x,y; 55 char s[10]; 56 scanf("%d",&T); 57 for ( h=1;h<=T;h++ ) { 58 scanf("%d",&n); 59 build(root); 60 printf("Case %d: ",h); 61 while ( scanf("%s",s) && s[0]!='E' ) { 62 scanf("%d%d",&x,&y); 63 if ( s[0]=='Q' ) { 64 printf("%d ",query(x,y,root)); 65 } 66 else if ( s[0]=='A' ) update(x,y,root); 67 else if ( s[0]=='S' ) update(x,-y,root); 68 } 69 } 70 return 0; 71 }
2.(POJ3468)http://poj.org/problem?id=3468
成段更新模板题

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 typedef long long ll; 9 const int maxn=100005; 10 struct node{ 11 ll sum; 12 }arr[maxn*4]; 13 ll add[maxn*4]; //延迟标记 14 15 void pushup(int rt) 16 { 17 arr[rt].sum=arr[rt*2].sum+arr[rt*2+1].sum; 18 } 19 20 void pushdown(int rt,int m) 21 { 22 if ( add[rt] ) { 23 add[rt*2]+=add[rt]; 24 add[rt*2+1]+=add[rt]; 25 arr[rt*2].sum+=add[rt]*(m-m/2); 26 arr[rt*2+1].sum+=add[rt]*(m/2); 27 add[rt]=0; 28 } 29 } 30 31 void build(int l,int r,int rt) 32 { 33 add[rt]=0; 34 if ( l==r ) { 35 scanf("%lld",&arr[rt].sum); 36 return; 37 } 38 int m=(l+r)/2; 39 build(lson); 40 build(rson); 41 pushup(rt); 42 } 43 44 void update(int L,int R,int c,int l,int r,int rt) 45 { 46 if ( L<=l && r<=R ) { 47 add[rt]+=c; 48 arr[rt].sum+=(ll)c*(r-l+1); 49 return; 50 } 51 pushdown(rt,r-l+1); 52 int m=(l+r)/2; 53 if ( L<=m ) update(L,R,c,lson); 54 if ( m<R ) update(L,R,c,rson); 55 pushup(rt); 56 } 57 58 ll query(int L,int R,int l,int r,int rt) 59 { 60 if ( L<=l && r<=R ) return arr[rt].sum; 61 pushdown(rt,r-l+1); 62 int m=(l+r)/2; 63 ll ret=0; 64 if ( L<=m ) ret+=query(L,R,lson); 65 if ( m<R ) ret+=query(L,R,rson); 66 return ret; 67 } 68 69 int main() 70 { 71 int n,q,i,j,k,x,y,z; 72 ll ans; 73 char s[10]; 74 while ( scanf("%d%d",&n,&q)!=EOF ) { 75 build(root); 76 while ( q-- ) { 77 scanf("%s",s); 78 if ( s[0]=='C' ) { 79 scanf("%d%d%d",&x,&y,&z); 80 update(x,y,z,root); 81 } 82 else { 83 scanf("%d%d",&x,&y); 84 printf("%lld ",query(x,y,root)); 85 } 86 } 87 } 88 return 0; 89 }
3.(HDOJ1754)http://acm.hdu.edu.cn/showproblem.php?pid=1754
模板题,将求和改成求最大值即可

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=200005; 9 struct node{ 10 int maxx; 11 }arr[maxn*4]; 12 13 void pushup(int rt) 14 { 15 arr[rt].maxx=max(arr[rt*2].maxx,arr[rt*2+1].maxx); 16 } 17 18 void build(int l,int r,int rt) 19 { 20 if ( l==r ) { 21 scanf("%d",&arr[rt].maxx); 22 return; 23 } 24 int m=(l+r)/2; 25 build(lson); 26 build(rson); 27 pushup(rt); 28 } 29 30 void update(int p,int add,int l,int r,int rt) 31 { 32 if ( l==r ) { 33 arr[rt].maxx=add; 34 return; 35 } 36 int m=(l+r)/2; 37 if ( p<=m ) update(p,add,lson); 38 else update(p,add,rson); 39 pushup(rt); 40 } 41 42 int query(int L,int R,int l,int r,int rt) 43 { 44 if ( L<=l && r<=R ) return arr[rt].maxx; 45 int m=(l+r)/2; 46 int ret=0; 47 if ( L<=m ) ret=max(ret,query(L,R,lson)); 48 if ( R>m ) ret=max(ret,query(L,R,rson)); 49 return ret; 50 } 51 52 int main() 53 { 54 int n,m,i,j,k,x,y,z; 55 char s[10]; 56 while ( scanf("%d%d",&n,&m)!=EOF ) { 57 build(root); 58 while ( m-- ) { 59 scanf("%s%d%d",s,&x,&y); 60 if ( s[0]=='Q' ) printf("%d ",query(x,y,root)); 61 else update(x,y,root); 62 } 63 } 64 return 0; 65 }
4.(HDOJ1394)http://acm.hdu.edu.cn/showproblem.php?pid=1394
题意:给定一段长度为n的序列,每次可以将第一个数字移动到最后一次,每移动一次求一次逆序数对,最后输出最小的逆序数对
分析:线段树求逆序数对的原理是:每次只输入一个数,然后利用线段树算出前面已经存入线段树中比它大的数的个数。本题求出原来序列的逆序数对后采用递推的方式求出后几项:对于一个num[i]从第一位移动到最后一位时,逆序数对会减少num[i]-1,会增加n-num[i]

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=5005; 9 int sum[maxn*4],num[maxn]; 10 11 void pushup(int rt) 12 { 13 sum[rt]=sum[rt*2]+sum[rt*2+1]; 14 } 15 16 void update(int p,int l,int r,int rt) 17 { 18 if ( l==r ) { 19 sum[rt]++; 20 return; 21 } 22 int m=(l+r)/2; 23 if ( p<=m ) update(p,lson); 24 else update(p,rson); 25 pushup(rt); 26 } 27 28 int query(int L,int R,int l,int r,int rt) 29 { 30 if ( L<=l && r<=R ) return sum[rt]; 31 int m=(l+r)/2; 32 int ret=0; 33 if ( L<=m ) ret+=query(L,R,lson); 34 if ( R>m ) ret+=query(L,R,rson); 35 return ret; 36 } 37 38 int main() 39 { 40 int n,i,j,k,m,x,y,z,ans,now; 41 while ( scanf("%d",&n)!=EOF ) { 42 memset(sum,0,sizeof(sum)); 43 ans=0; 44 for ( i=1;i<=n;i++ ) { 45 scanf("%d",&x); 46 num[i]=++x; 47 } 48 for ( i=1;i<=n;i++ ) { 49 x=query(1,num[i],root); 50 y=i-1-x; 51 ans+=y; 52 update(num[i],root); 53 } 54 now=ans; 55 for ( i=1;i<=n;i++ ) { 56 now=now-(num[i]-1)+(n-num[i]); 57 ans=min(ans,now); 58 } 59 printf("%d ",ans); 60 } 61 return 0; 62 }
5.(HDOJ2795)http://acm.hdu.edu.cn/showproblem.php?pid=2795
题意;有一个n*w的公告栏,有q条消息,每条消息占据1*x的位置,消息摆放的位置是最上边最左边,每次给定消息输出位置
分析:附加值为最大值,每次访问判断最大值。边访问边更新,每次优先往左更新,返回位置。
注意:1.注意刚开始需要拿n和q进行比较,不然n的范围太大存不了。 2.build的时候将所有maxx[rt]都变成w即可。 3.每次给定长度时直接判断maxx[1]是否满足条件。 4.注意边query边update的写法

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=2e5+10; 9 int w,maxx[maxn*4]; 10 11 void pushup(int rt) 12 { 13 maxx[rt]=max(maxx[rt*2],maxx[rt*2+1]); 14 } 15 16 void build(int l,int r,int rt) 17 { 18 maxx[rt]=w; 19 if ( l==r ) return; 20 int m=(l+r)/2; 21 build(lson); 22 build(rson); 23 } 24 25 int query(int x,int l,int r,int rt) 26 { 27 if ( l==r ) { 28 maxx[rt]-=x; 29 return l; 30 } 31 int m=(l+r)/2; 32 int ret; 33 if ( maxx[rt*2]>=x ) ret=query(x,lson); 34 else ret=query(x,rson); 35 pushup(rt); 36 return ret; 37 } 38 39 int main() 40 { 41 int n,i,j,k,m,x,y,q; 42 while ( scanf("%d%d%d",&n,&w,&q)!=EOF ) { 43 if ( n>q ) n=q; 44 build(root); 45 while ( q-- ) { 46 scanf("%d",&x); 47 if ( maxx[1]<x ) printf("-1 "); 48 else printf("%d ",query(x,root)); 49 } 50 } 51 return 0; 52 }
6.(POJ2828)http://poj.org/problem?id=2828
题意:有n个人,第i个人会排在当前pos[i]位置后面的那个位置,每人有一个编号,求最后队伍从头到尾的编号
分析:因为后面每次操作会影响前面人的位置,所有考虑从最后开始考虑。
我的思路(WA):对于第i个人最初应该站在cnt[i]=pos[i]+1的位置上,随着后面人的加入他的位置会不断往后,但是往后多少呢?首先可以求出在该项(第i项)以后(i<j<=n)所有项中cnt[j]<=cnt[i]的位置有多少个(这里用x表示满足条件的位置的个数),表示的含义是后面有多少人插到了他的前面(即第i个人应该坐到从cnt[i]开始数,第x个空位置上)。用线段树来维护空位置的个数(返回位置下标),同时还需要用线段树来维护第i项往后位置<=cnt[i]的个数。但是不知道为啥WA了...
正确思路(AC):用线段树来维护空位置的个数。首先考虑最后一个人(即第n个人),最后一个人的位置不受前面任何人的影响,所有可以直接放入队列当中,即cnt[n]这个位置被占据。而对倒数第二个人(即n-1)来说,若cnt[n-1]<cnt[n],那么第n-1所坐的位置不受第n个人的影响。若cnt[n-1]>=cnt[n],因为cnt[n],已经被占据,所以第n-1个人的位置受到影响自动延后一个。总的来说就是每次做到第cnt[i]个空位置上。用线段树来维护区间范围内空位置的个数。对于元素来说是从头到尾逐一添加,边访问边修改

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=2e5+10; 9 int ans[maxn],sum[maxn*4]; 10 struct node{ 11 int pos; 12 int val; 13 }arr[maxn]; 14 15 void pushup(int rt) 16 { 17 sum[rt]=sum[rt*2]+sum[rt*2+1]; 18 } 19 20 void build(int l,int r,int rt) 21 { 22 if ( l==r ) { 23 sum[rt]=1; 24 return; 25 } 26 int m=(l+r)/2; 27 build(lson); 28 build(rson); 29 pushup(rt); 30 } 31 32 int query(int p,int l,int r,int rt) 33 { 34 if ( l==r ) { 35 sum[rt]=0; 36 return l; 37 } 38 int m=(l+r)/2; 39 int ret=0; 40 if ( sum[rt*2]>=p ) ret=query(p,lson); 41 else ret=query(p-sum[rt*2],rson); 42 pushup(rt); 43 return ret; 44 } 45 46 int main() 47 { 48 int n,i,j,k,x,y,z; 49 while ( scanf("%d",&n)!=EOF ) { 50 build(root); 51 for ( i=0;i<n;i++ ) { 52 scanf("%d%d",&x,&arr[i].val); 53 arr[i].pos=x+1; 54 } 55 for ( i=n-1;i>=0;i-- ) { 56 x=query(arr[i].pos,root); 57 ans[x]=arr[i].val; 58 } 59 for ( i=1;i<=n;i++ ) { 60 printf("%d",ans[i]); 61 if ( i!=n ) printf(" "); 62 else printf(" "); 63 } 64 } 65 return 0; 66 }
7.(POJ2452)http://poj.org/problem?id=2452
题意:给定一段长度为n的序列,先求一段最长的区间满足开头si为最小,sj为最大,中间的数都比si大比sj小。
分析: 因为既要求一个大的值又要求一个小的值,那么我们将其中一个固定求另一个,即把每项都当作最小项,在他的后面去求最大。首先计算出第i项后有多少项大于si(记作cnt[i]),然后利用线段树贮存区间的最大值,对于每一项求出i到i+cnt[i]这个范围内的最大值,然后不断更新ans。但是用线段树做不知道为什么WA了,后来借鉴了网络上的路径压缩的方法十分巧妙,值得一学。

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 typedef long long ll; 9 const ll maxn=1e5+10; 10 ll num[maxn],cnt[maxn],maxx[maxn*4],pos[maxn*4]; 11 12 void pushup(ll rt) 13 { 14 if ( maxx[rt*2]>=maxx[rt*2+1] ) { 15 maxx[rt]=maxx[rt*2]; 16 pos[rt]=pos[rt*2]; 17 } 18 else { 19 maxx[rt]=maxx[rt*2+1]; 20 pos[rt]=pos[rt*2+1]; 21 } 22 } 23 24 void build(ll l,ll r,ll rt) 25 { 26 if ( l==r ) { 27 maxx[rt]=num[l]; 28 pos[rt]=l; 29 return; 30 } 31 ll m=(l+r)/2; 32 build(lson); 33 build(rson); 34 pushup(rt); 35 } 36 37 ll query(ll L,ll R,ll l,ll r,ll rt) 38 { 39 if ( L<=l && r<=R ) return pos[rt]; 40 ll m=(l+r)/2; 41 if ( maxx[rt*2]==maxx[rt] ) return query(L,R,lson); 42 else return query(L,R,rson); 43 } 44 45 int main() 46 { 47 ll n,i,j,k,x,y,z,ans,now; 48 while ( scanf("%lld",&n)!=EOF ) { 49 for ( i=1;i<=n;i++ ) scanf("%lld",&num[i]); 50 memset(cnt,0,sizeof(cnt)); 51 for ( i=1;i<=n;i++ ) { 52 for ( j=i+1;j<=n;j++ ) { 53 if ( num[j]>num[i] ) cnt[i]++; 54 else break; 55 } 56 } 57 build(root); 58 ans=-1; 59 for ( i=1;i<=n;i++ ) { 60 if ( cnt[i]>0 ) { 61 now=query(i,i+cnt[i],root)-i; 62 ans=max(now,ans); 63 } 64 } 65 printf("%lld ",ans); 66 } 67 return 0; 68 }

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=5e4+10; 6 int num[maxn],cnt[maxn]; //num记录初始的数组,cnt[i]-1表示从i后面有多少个连续的数大于num[i] 7 8 int main() 9 { 10 int i,j,k,n,m,x,y,z,ans,now,maxx,add; 11 while ( scanf("%d",&n)!=EOF ) { 12 for ( i=1;i<=n;i++ ) { 13 scanf("%d",&num[i]); 14 cnt[i]=1; 15 } 16 cnt[n+1]=-1; //主要要对末尾进行特殊处理 17 ans=0; 18 for ( i=n;i>0;i-- ) { //从后往前计算 19 while ( num[i]<num[i+cnt[i]] ) { //使得每次不止跳1的长度 20 cnt[i]+=cnt[i+cnt[i]]; 21 } 22 } 23 for ( i=1;i<=n;i+=(add+1) ) { //第i次结束后跳到对于i来说的最大值的下一个位置 24 maxx=add=-1; //maxx记录最大值,add记录长度 25 for ( j=0;j<cnt[i];j++ ) { 26 if ( num[i+j]>maxx ) { 27 maxx=num[i+j]; 28 add=j; 29 } 30 } 31 ans=max(ans,add); 32 } 33 if ( ans ) printf("%d ",ans); 34 else printf("-1 "); 35 } 36 return 0; 37 }
区间染色
1.(HDOJ1689)http://acm.hdu.edu.cn/showproblem.php?pid=1698
题意:一条铁链有n段,初始时每段价值都是1,进行q次操作,每次操作给出x,y,z,表示将x到y这段区域中所有的子段替换成价值为z。求最后这个铁链的价值
分析:为经典的区间染色题,将模板进行稍许的修改即可

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=100500; 9 struct node{ 10 int sum; 11 }arr[maxn*4]; 12 int add[maxn*4]; 13 14 void pushup(int rt) 15 { 16 arr[rt].sum=arr[rt*2].sum+arr[rt*2+1].sum; 17 } 18 19 void pushdown(int rt,int m) 20 { 21 if ( add[rt] ) { 22 add[rt*2]=add[rt]; 23 add[rt*2+1]=add[rt]; 24 arr[rt*2].sum=add[rt]*(m-m/2); 25 arr[rt*2+1].sum=add[rt]*(m/2); 26 add[rt]=0; 27 } 28 } 29 30 void build(int l,int r,int rt) 31 { 32 add[rt]=0; 33 if ( l==r ) { 34 arr[rt].sum=1; 35 return; 36 } 37 int m=(l+r)/2; 38 build(lson); 39 build(rson); 40 pushup(rt); 41 } 42 43 void update(int L,int R,int c,int l,int r,int rt) 44 { 45 if ( L<=l && r<=R ) { 46 add[rt]=c; 47 arr[rt].sum=c*(r-l+1); 48 return; 49 } 50 pushdown(rt,r-l+1); 51 int m=(l+r)/2; 52 if ( L<=m ) update(L,R,c,lson); 53 if ( m<R ) update(L,R,c,rson); 54 pushup(rt); 55 } 56 57 int query(int L,int R,int l,int r,int rt) 58 { 59 if ( L<=l && r<=R ) return arr[rt].sum; 60 pushdown(rt,r-l+1); 61 int m=(l+r)/2; 62 int ret=0; 63 if ( L<=m ) ret+=query(L,R,lson); 64 if ( m<R ) ret+=query(L,R,rson); 65 return ret; 66 } 67 68 int main() 69 { 70 int i,j,k,T,x,y,z,n,m,q,h; 71 scanf("%d",&T); 72 for ( h=1;h<=T;h++ ) { 73 scanf("%d",&n); 74 build(root); 75 scanf("%d",&q); 76 while ( q-- ) { 77 scanf("%d%d%d",&x,&y,&z); 78 update(x,y,z,root); 79 } 80 printf("Case %d: The total value of the hook is %d. ",h,arr[1].sum); 81 } 82 return 0; 83 }
2.(HDOJ3308)http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:给定一段序列,有两种操作:1.单点替换,2.区间查找最长连续递增子串的长度
分析:考察区间合并,使用数组较为方便。

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=1e5+10; 9 int lmax[maxn*4],rmax[maxn*4],num[maxn],maxx[maxn*4]; 10 //lmax表示一段中前缀的最长递增子串,rmax表示后缀的,maxx表示整个区间的 11 //特别注意num,是按照序号存储本身的值,而不表示一段一段 12 13 void pushup(int l,int r,int rt) 14 { 15 int x,y; 16 int m=(l+r)/2; //区间中值 17 int len=r-l+1; //区间长度 18 //在不考虑合并区间时有以下三个操作 19 maxx[rt]=max(maxx[rt*2],maxx[rt*2+1]); 20 lmax[rt]=lmax[rt*2]; 21 rmax[rt]=rmax[rt*2+1]; 22 if ( num[m+1]>num[m] ) { //当两个区间满足条件即可合并 23 x=rmax[rt*2]+lmax[rt*2+1]; 24 maxx[rt]=max(maxx[rt],x); 25 if ( lmax[rt*2]==(len-len/2) ) lmax[rt]+=lmax[rt*2+1]; 26 if ( rmax[rt*2+1]==len/2 ) rmax[rt]+=rmax[rt*2]; 27 } 28 } 29 30 void build(int l,int r,int rt) 31 { 32 if ( l==r ) { 33 scanf("%d",&num[l]); 34 maxx[rt]=lmax[rt]=rmax[rt]=1; 35 return; 36 } 37 maxx[rt]=lmax[rt]=rmax[rt]=0; 38 int m=(l+r)/2; 39 build(lson); 40 build(rson); 41 pushup(l,r,rt); 42 } 43 44 void update(int p,int add,int l,int r,int rt) 45 { 46 if ( l==r ) { 47 num[p]=add; 48 return; 49 } 50 int m=(l+r)/2; 51 if ( p<=m ) update(p,add,lson); 52 else update(p,add,rson); 53 pushup(l,r,rt); 54 } 55 56 int query(int L,int R,int l,int r,int rt) 57 { 58 if ( L<=l && r<=R ) return maxx[rt]; 59 int m=(l+r)/2; 60 int ret=0; 61 if ( L<=m ) ret=max(ret,query(L,R,lson)); 62 if ( R>m ) ret=max(ret,query(L,R,rson)); 63 //以下还有一个区间合并的操作 64 if ( num[m]<num[m+1] ) { 65 int c=min(rmax[rt*2],m-L+1)+min(lmax[rt*2+1],R-m); 66 //可能左子树的范围会超过所要求解区间的左半部分,所有取两个中较小的那个。右边同理 67 ret=max(ret,c); 68 } 69 return ret; 70 } 71 72 int main() 73 { 74 int T,i,j,k,n,m,x,y; 75 char s[10]; 76 scanf("%d",&T); 77 while ( T-- ) { 78 scanf("%d%d",&n,&m); 79 build(1,n,1); 80 while ( m-- ) { 81 scanf("%s%d%d",s,&x,&y); 82 x++; //因为模板是从1开始的,而题目的编号从0开始 83 if ( s[0]=='U' ) update(x,y,root); 84 else printf("%d ",query(x,++y,root)); 85 } 86 } 87 return 0; 88 }
3.(POJ3368)http://poj.org/problem?id=3368
题意:从小到大给定一段长度为n的序列,有q次询问,每次询问给定一段[x,y],求在[x,y]范围内出现最频繁数出现的次数
分析:和上题类似,考察区间合并。序列本身的值存在num[]中,设置3个数组分别维护前缀的最大长度、后缀的最大长度以及整个段的最大长度

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=1e5+10; 9 int num[maxn],lmax[maxn*4],rmax[maxn*4],maxx[maxn*4]; 10 11 void pushup(int l,int r,int rt) 12 { 13 int m=(l+r)/2; 14 int len=r-l+1; 15 maxx[rt]=max(maxx[rt*2],maxx[rt*2+1]); 16 lmax[rt]=lmax[rt*2]; 17 rmax[rt]=rmax[rt*2+1]; 18 if ( num[m]==num[m+1] ) { 19 maxx[rt]=max(maxx[rt],rmax[rt*2]+lmax[rt*2+1]); 20 if ( lmax[rt*2]==(len-len/2) ) lmax[rt]+=lmax[rt*2+1]; 21 if ( rmax[rt*2+1]==len/2 ) rmax[rt]+=rmax[rt*2]; 22 } 23 } 24 25 void build(int l,int r,int rt) 26 { 27 if ( l==r ) { 28 scanf("%d",&num[l]); 29 maxx[rt]=lmax[rt]=rmax[rt]=1; 30 return; 31 } 32 int m=(l+r)/2; 33 build(lson); 34 build(rson); 35 pushup(l,r,rt); 36 } 37 38 int query(int L,int R,int l,int r,int rt) 39 { 40 if ( L<=l && r<=R ) return maxx[rt]; 41 int m=(l+r)/2; 42 int ret=0; 43 if ( L<=m ) ret=max(ret,query(L,R,lson)); 44 if ( R>m ) ret=max(ret,query(L,R,rson)); 45 if ( num[m]==num[m+1] ) { 46 int c=min(rmax[rt*2],m-L+1)+min(lmax[rt*2+1],R-m); 47 ret=max(ret,c); 48 } 49 return ret; 50 } 51 52 int main() 53 { 54 int n,i,j,k,q,x,y; 55 while ( scanf("%d",&n)!=EOF && n ) { 56 scanf("%d",&q); 57 build(root); 58 while ( q-- ) { 59 scanf("%d%d",&x,&y); 60 printf("%d ",query(x,y,root)); 61 } 62 } 63 return 0; 64 }
4.(POJ2777)http://poj.org/problem?id=2777
题意:给定一段长度为n的序列,用数字表示颜色,起初序列全为1,存在两种操作:1.将某一段全部替换成另一种颜色 2.输出某一段存在的颜色个数
分析:采用二进制的思想,对于颜色i来说用1<<(i-1)表示。当求有几种颜色的时候用|进行叠加,最后还原出一个数在二进制下多少个1,即为有几种颜色。同时特别注意给定的区间可能前面大于后面注意一定要交换

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 typedef long long ll; 9 const ll maxn=1e5+10; 10 ll sum[maxn*4],add[maxn*4],w; 11 12 void pushup(ll rt) 13 { 14 sum[rt]=sum[rt*2]|sum[rt*2+1]; 15 } 16 17 void pushdown(ll rt,ll m) 18 { 19 if ( add[rt] ) { 20 add[rt*2]=add[rt]; 21 add[rt*2+1]=add[rt]; 22 sum[rt*2]=1<<(add[rt]-1); 23 sum[rt*2+1]=1<<(add[rt]-1); 24 add[rt]=0; 25 } 26 } 27 28 void build(ll l,ll r,ll rt) 29 { 30 add[rt]=0; 31 if ( l==r ) { 32 sum[rt]=1; 33 return; 34 } 35 ll m=(l+r)/2; 36 build(lson); 37 build(rson); 38 pushup(rt); 39 } 40 41 void update(ll L,ll R,ll c,ll l,ll r,ll rt) 42 { 43 if ( L<=l && r<=R ) { 44 add[rt]=c; 45 sum[rt]=1<<(c-1); 46 return; 47 } 48 pushdown(rt,r-l+1); 49 ll m=(l+r)/2; 50 if ( L<=m ) update(L,R,c,lson); 51 if ( m<R ) update(L,R,c,rson); 52 pushup(rt); 53 } 54 55 ll query(ll L,ll R,ll l,ll r,ll rt) 56 { 57 if ( L<=l && r<=R ) return sum[rt]; 58 pushdown(rt,r-l+1); 59 ll m=(l+r)/2; 60 ll ret=0; 61 if ( L<=m ) ret|=query(L,R,lson); 62 if ( m<R ) ret|=query(L,R,rson); 63 return ret; 64 } 65 66 ll judge(ll x) 67 { 68 ll cnt=0; 69 for ( ll i=0;i<w;i++ ) { 70 if ( x&(1<<(i)) ) cnt++; 71 } 72 return cnt; 73 } 74 75 int main() 76 { 77 ll n,m,x,y,z,u,v,i,j,k; 78 char s[10]; 79 while ( scanf("%lld%lld%lld",&n,&w,&m)!=EOF ) { 80 build(root); 81 memset(add,0,sizeof(add)); 82 for ( i=0;i<m;i++ ) { 83 scanf("%s",s); 84 if ( s[0]=='C' ) { 85 scanf("%lld%lld%lld",&x,&y,&z); 86 if ( x>y ) swap(x,y); 87 update(x,y,z,root); 88 } 89 else { 90 scanf("%lld%lld",&x,&y); 91 if ( x>y ) swap(x,y); 92 u=query(x,y,root); 93 printf("%lld ",judge(u)); 94 } 95 } 96 } 97 return 0; 98 }
5.(POJ3667)http://poj.org/problem?id=3667
离线操作
小结:一般都是对某一区间满足某个条件的一些数进行操作。这时候需要将访问的区间存起来。按照某一规则进行排列。对于每一个访问去除掉那些不符合条件的数。这样可以将其变成普通线段树,对于每个访问就是先更新某个值,在进行询问操作。
1.(HDOJ4417)http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:有一条长度为n的管道,每段高为h[i],有m个询问,每次询问给出x,y,z代表在[x,y]这个范围内他的跳跃高度z,对于每次询问输出可以撞到几段的顶部(即z>=h[i]算撞到)
首先转变一下题意:有一个长度为n的序列,每项的值为num[i],给出一段访问区间和一个数k,求在这个范围内<=k的的数有多少
分析:采用线段树离线操作,将所有询问先保存下来。将每个询问按h从大到小进行排序,对于第i个询问,在该区间中将所有num[i]>h的一段去除。剩下的部分采用线段树经典求和即可。初始化将所有叶子节点的sum[rt]=1,对于每个num[i]>=h的那段,将第i个位置的sum更新为0。但是因为对于每个区间查找需要O(n)的复杂度,会倒是超时

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=1e5+10; 9 int sum[maxn*4],num[maxn],ans[maxn]; 10 struct node{ 11 int l; 12 int r; 13 int h; 14 int index; 15 }arr[maxn]; 16 17 void pushup(int rt) 18 { 19 sum[rt]=sum[rt*2]+sum[rt*2+1]; 20 } 21 22 void build(int l,int r,int rt) 23 { 24 if ( l==r ) { 25 sum[rt]=1; 26 return; 27 } 28 int m=(l+r)/2; 29 build(lson); 30 build(rson); 31 pushup(rt); 32 } 33 34 void update(int p,int l,int r,int rt) 35 { 36 if ( l==r ) { 37 sum[rt]=0; 38 return; 39 } 40 int m=(l+r)/2; 41 if ( p<=m ) update(p,lson); 42 else update(p,rson); 43 pushup(rt); 44 } 45 46 int query(int L,int R,int l,int r,int rt) 47 { 48 if ( L<=l && r<=R ) return sum[rt]; 49 int m=(l+r)/2; 50 int ret=0; 51 if ( L<=m ) ret+=query(L,R,lson); 52 if ( R>m ) ret+=query(L,R,rson); 53 return ret; 54 } 55 56 bool cmp(node a,node b) 57 { 58 return a.h>b.h; 59 } 60 61 int main() 62 { 63 int T,i,j,k,h,n,m; 64 scanf("%d",&T); 65 for ( h=1;h<=T;h++ ) { 66 scanf("%d%d",&n,&m); 67 for ( i=1;i<=n;i++ ) scanf("%d",&num[i]); 68 build(root); 69 for ( i=1;i<=m;i++ ) { 70 scanf("%d%d%d",&arr[i].l,&arr[i].r,&arr[i].h); 71 arr[i].l++; 72 arr[i].r++; 73 arr[i].index=i; 74 } 75 sort(arr+1,arr+m+1,cmp); 76 for ( i=1;i<=m;i++ ) { 77 for ( j=arr[i].l;j<=arr[i].r;j++ ) { 78 if ( num[j]>arr[i].h ) { 79 update(j,root); 80 } 81 } 82 ans[arr[i].index]=query(arr[i].l,arr[i].r,root); 83 } 84 printf("Case %d: ",h); 85 for ( i=1;i<=m;i++ ) printf("%d ",ans[i]); 86 } 87 return 0; 88 }
所以改进查找区间范围内>k的数的范围。将其(对于每一个i,都有num和index=i两项)保存在结构体,按照num的值从大到小进行排列,每次查找时都接着上次查找结束的位置继续查找,可以将全体范围内>k的数都删除。

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define lson l,m,rt*2 6 #define rson m+1,r,rt*2+1 7 #define root 1,n,1 8 const int maxn=1e5+10; 9 int sum[maxn*4],num[maxn],ans[maxn]; 10 struct node{ 11 int l; 12 int r; 13 int h; 14 int index; 15 }arr[maxn]; 16 struct node_{ 17 int val; 18 int index; 19 }arr_[maxn]; 20 21 void pushup(int rt) 22 { 23 sum[rt]=sum[rt*2]+sum[rt*2+1]; 24 } 25 26 void build(int l,int r,int rt) 27 { 28 if ( l==r ) { 29 sum[rt]=1; 30 return; 31 } 32 int m=(l+r)/2; 33 build(lson); 34 build(rson); 35 pushup(rt); 36 } 37 38 void update(int p,int l,int r,int rt) 39 { 40 if ( l==r ) { 41 sum[rt]=0; 42 return; 43 } 44 int m=(l+r)/2; 45 if ( p<=m ) update(p,lson); 46 else update(p,rson); 47 pushup(rt); 48 } 49 50 int query(int L,int R,int l,int r,int rt) 51 { 52 if ( L<=l && r<=R ) return sum[rt]; 53 int m=(l+r)/2; 54 int ret=0; 55 if ( L<=m ) ret+=query(L,R,lson); 56 if ( R>m ) ret+=query(L,R,rson); 57 return ret; 58 } 59 60 bool cmp(node a,node b) 61 { 62 return a.h>b.h; 63 } 64 65 bool cmp_(node_ a,node_ b) 66 { 67 return a.val>b.val; 68 } 69 70 int main() 71 { 72 int T,i,j,h,n,m,cnt; 73 scanf("%d",&T); 74 for ( h=1;h<=T;h++ ) { 75 scanf("%d%d",&n,&m); 76 for ( i=1;i<=n;i++ ) { 77 scanf("%d",&arr_[i].val); 78 arr_[i].index=i; 79 } 80 sort(arr_+1,arr_+n+1,cmp_); 81 build(root); 82 for ( i=1;i<=m;i++ ) { 83 scanf("%d%d%d",&arr[i].l,&arr[i].r,&arr[i].h); 84 arr[i].l++; 85 arr[i].r++; 86 arr[i].index=i; 87 } 88 sort(arr+1,arr+m+1,cmp); 89 cnt=1; 90 for ( i=1;i<=m;i++ ) { 91 for ( j=cnt;j<=n;j++&&cnt++ ) { 92 if ( arr_[j].val>arr[i].h ) { 93 update(arr_[j].index,root); 94 } 95 else break; 96 } 97 ans[arr[i].index]=query(arr[i].l,arr[i].r,root); 98 } 99 printf("Case %d: ",h); 100 for ( i=1;i<=m;i++ ) printf("%d ",ans[i]); 101 } 102 return 0; 103 }
2.(HDOJ3333)http://acm.hdu.edu.cn/showproblem.php?pid=3333 (HDOJ3874同,只是那道题数据范围更小)
题意:有一段长度为n的序列,每次给定一个范围,求这个范围内不相等数的和
分析:如果一次将所有值都存入线段树内则无法判断哪些数相等。所有采用先将所有访问按照右边界的值从小到大排列(至于这么做为什么可以?因为对于每个重复的数来说,只有从右端点起向左的第一个数才是有效的,其他的都是无用的),然后再依次添加。同时用map记录每个数对应的下标,如果遇到相同的数,则将之前位置的那个数变成0,同时更新map。

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 using namespace std; 6 #define lson l,m,rt*2 7 #define rson m+1,r,rt*2+1 8 #define root 1,n,1 9 typedef long long ll; 10 const ll maxn=1e5+10; 11 const ll maxm=1e5+10; 12 ll sum[maxn*4],num[maxn],ans[maxn]; 13 map<ll,ll>mp; 14 struct node{ 15 ll l; 16 ll r; 17 ll index; 18 }arr[maxm]; 19 20 void pushup(ll rt) 21 { 22 sum[rt]=sum[rt*2]+sum[rt*2+1]; 23 } 24 25 void build(ll l,ll r,ll rt) 26 { 27 if ( l==r ) { 28 sum[rt]=num[l]; 29 return; 30 } 31 ll m=(l+r)/2; 32 build(lson); 33 build(rson); 34 pushup(rt); 35 } 36 37 void update(ll p,ll l,ll r,ll rt) 38 { 39 if ( l==r ) { 40 sum[rt]=0; 41 return; 42 } 43 ll m=(l+r)/2; 44 if ( p<=m ) update(p,lson); 45 else update(p,rson); 46 pushup(rt); 47 } 48 49 ll query(ll L,ll R,ll l,ll r,ll rt) 50 { 51 if ( L<=l && r<=R ) return sum[rt]; 52 ll m=(l+r)/2; 53 ll ret=0; 54 if ( L<=m ) ret+=query(L,R,lson); 55 if ( m<R ) ret+=query(L,R,rson); 56 return ret; 57 } 58 59 bool cmp(node a,node b) 60 { 61 return a.r<b.r; 62 } 63 64 int main() 65 { 66 ll T,i,j,k,n,m,x,y,z,cnt; 67 scanf("%lld",&T); 68 while ( T-- ) { 69 scanf("%lld",&n); 70 mp.clear(); 71 for ( i=1;i<=n;i++ ) scanf("%lld",&num[i]); 72 build(root); 73 scanf("%lld",&m); 74 for ( i=1;i<=m;i++ ) { 75 scanf("%lld%lld",&arr[i].l,&arr[i].r); 76 arr[i].index=i; 77 } 78 sort(arr+1,arr+1+m,cmp); 79 cnt=1; 80 for ( i=1;i<=m;i++ ) { 81 for ( ;cnt<=arr[i].r;cnt++ ) { 82 if ( mp[num[cnt]]!=0 ) update(mp[num[cnt]],root); 83 mp[num[cnt]]=cnt; 84 } 85 ans[arr[i].index]=query(arr[i].l,arr[i].r,root); 86 } 87 for ( i=1;i<=m;i++ ) printf("%I64d ",ans[i]); 88 } 89 return 0; 90 }
DFS序和线段树
DFS序:即将原本的树状结构转化成线性结构,通过DFS记录进栈的时间戳in[i]和出栈的时间戳out[i],而[in[i],out[i]]为该节点所维护的区间,对于任意处于[in[i]+1,out[i]]都是i的子节点。建树时对于结点i将所维护的值添加到in[i]这个位置即可。每次对某个节点操作时就是对该节点所在的区间进行操作。
1.(HDOJ4366)http://acm.hdu.edu.cn/showproblem.php?pid=4366
题意:先总共有n个人,老板的编号为n,员工的编号从1到n-1,每个人都有一个能力值和忠诚度和对应上司。现在老板要解雇几个人,对于每一个解雇的人,从能力值大于他的下属中(直接/间接)选择忠诚度最高的来接替他。
分析:离线处理+DFS序+线段树
DFS序将原本的关系网(树)转化成线性结构。因为选择的下属能力值必须要大于上司,所有将能力值按从大到小进行排序、操作(离线操作),每次访问他的子节点中(即[in[i]+1,out[i]]这个区间)忠诚度最大的(利用map将忠诚度和编号对应,这样得到能力值就知道编号了),然后将其添加到线段树中。另一个关键是如何处理能力值相同的人,添加的顺序会影响最终的结果,所以排序时将id小的排在后面(id小的会影响id大的)
2.(HDOJ3974)http://acm.hdu.edu.cn/showproblem.php?pid=3974
题意:有n个员工编号从1到n,有n-1条关系每条关系输入x,y,表示y是x的上司。有m条操作,有两类操作第一类是分配给某个人一项任务(则他的全部下属全部和他做同样的工作,有新工作时直接覆盖),另一种是查询某个人当前在做什么工作
分析:DFS序+线段树。因为是关系网(树状结构),所有采用DFS序将其转化成线性结构。当上司做一项工作时他的属下全部和上司做一样的工作,那么我们可以采用线段树当中的替换。于此同时我们可以设置一个父节点,和那些没有父亲的点相连。

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 #define lson l,m,rt*2 7 #define rson m+1,r,rt*2+1 8 #define root 1,cnt,1 9 const int maxn=1e5+10; 10 int a[maxn*4],add[maxn*4],cnt,in[maxn],out[maxn]; 11 bool vis[maxn]; 12 vector<int>G[maxn]; 13 14 void pushdown(int rt,int m) 15 { 16 if ( add[rt] ) { 17 add[rt*2]=add[rt]; 18 add[rt*2+1]=add[rt]; 19 a[rt*2]=add[rt]; 20 a[rt*2+1]=add[rt]; 21 add[rt]=0; 22 } 23 } 24 25 void build(int l,int r,int rt) 26 { 27 add[rt]=0; 28 a[rt]=-1; 29 if ( l==r ) return; 30 int m=(l+r)/2; 31 build(lson); 32 build(rson); 33 } 34 35 void update(int L,int R,int c,int l,int r,int rt) 36 { 37 if ( L<=l && r<=R ) { 38 add[rt]=c; 39 a[rt]=c; 40 return; 41 } 42 pushdown(rt,r-l+1); 43 int m=(l+r)/2; 44 if ( L<=m ) update(L,R,c,lson); 45 if ( m<R ) update(L,R,c,rson); 46 } 47 48 int query(int L,int R,int l,int r,int rt) 49 { 50 if ( L<=l && r<=R ) return a[rt]; 51 pushdown(rt,r-l+1); 52 int m=(l+r)/2; 53 if ( L<=m ) return query(L,R,lson); 54 else return query(L,R,rson); 55 } 56 57 void DFS(int u) 58 { 59 in[u]=++cnt; 60 for ( int i=0;i<G[u].size();i++ ) { 61 int v=G[u][i]; 62 DFS(v); 63 } 64 out[u]=cnt; 65 } 66 67 int main() 68 { 69 int T,i,j,k,h,x,y,z,n,m; 70 char s[10]; 71 scanf("%d",&T); 72 for ( h=1;h<=T;h++ ) { 73 scanf("%d",&n); 74 for ( i=0;i<=n;i++ ) { 75 G[i].clear(); 76 vis[i]=false; 77 } 78 for ( i=1;i<n;i++ ) { 79 scanf("%d%d",&x,&y); 80 G[y].push_back(x); 81 vis[x]=true; 82 } 83 for ( i=1;i<=n;i++ ) { 84 if ( !vis[i] ) { 85 G[0].push_back(i); 86 } 87 } 88 cnt=0; 89 DFS(0); 90 memset(a,-1,sizeof(a)); 91 memset(add,0,sizeof(add)); 92 printf("Case #%d: ",h); 93 scanf("%d",&m); 94 while ( m-- ) { 95 scanf("%s",s); 96 if ( s[0]=='T' ) { 97 scanf("%d%d",&x,&y); 98 update(in[x],out[x],y,root); 99 } 100 else { 101 scanf("%d",&x); 102 printf("%d ",query(in[x],out[x],root)); 103 } 104 } 105 } 106 return 0; 107 }
3.(HDOJ5692)http://acm.hdu.edu.cn/showproblem.php?pid=5692
区间合并