Codeforces Round #250 (Div. 1)D:http://codeforces.com/problemset/problem/438/D
题意:给你一个序列,然后有3种操作 1x y.表示查询[x,y]之间的区间和,2 x y z表示把[x y]内的数%z,3x y,表示把第x个数变成y。
题解:肯定是用线段树来维护,但是一开始想不到维护什么统计量,对于区间取模,没办法用lazy标记,更新到第的话,肯定会T。后来,认为既然没办法用lazy,那么只能用别的方法来优化更新。发现每次取模之后,数都会变小,如果要取模的数比当前模数小的话,就不用取模,于是可以维护区间最大值,如果区间最大值都小于模数的话,这个区间肯定不用更新,这样来减少更新。这样的方法,其实以前也做过,就是对于一个区间内的数进行开平方操作,每个数会越开越小,到了1的时候就可以直接不开了。因此,对于线段树的区间更新来说:1如果能找到好的lazy可以标记的话,就使用lazy标记;2如果找不到就要想办法优化区间更新,让单点更新的次数变少。另外此题,自己用线段树省空间的写法,结果不熟练,一个地方写错,最后wa几发。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int N=1e5+19; 7 int n,m; 8 long long sum[N*4],maxn[N*4]; 9 void pushup(int rt){ 10 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 11 maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]); 12 } 13 void build(int l,int r,int rt){ 14 if(l==r){ 15 scanf("%I64d",&maxn[rt]); 16 sum[rt]=maxn[rt]; 17 return; 18 } 19 int mid=(l+r)/2; 20 build(l,mid,rt<<1); 21 build(mid+1,r,rt<<1|1); 22 pushup(rt); 23 } 24 void update(int l,int r,int rt,int from,int to,long long mod){ 25 if(maxn[rt]<mod)return; 26 if(l==r){ 27 maxn[rt]%=mod; 28 sum[rt]=maxn[rt]; 29 return; 30 } 31 int mid=(l+r)/2; 32 if(mid>=to)update(l,mid,rt<<1,from,to,mod); 33 else if(mid<from)update(mid+1,r,rt<<1|1,from,to,mod); 34 else{ 35 update(l,mid,rt<<1,from,mid,mod); 36 update(mid+1,r,rt<<1|1,mid+1,to,mod); 37 } 38 pushup(rt); 39 } 40 void update2(int l,int r,int rt,int pos,long long val){ 41 if(l==r){ 42 maxn[rt]=val; 43 sum[rt]=val; 44 return; 45 } 46 int mid=(l+r)/2; 47 if(mid>=pos)update2(l,mid,rt<<1,pos,val); 48 else update2(mid+1,r,rt<<1|1,pos,val); 49 pushup(rt); 50 } 51 long long query(int l,int r,int rt,int from,int to){ 52 if(l==from&&r==to){ 53 return sum[rt]; 54 } 55 int mid=(l+r)/2; 56 if(mid>=to)return query(l,mid,rt<<1,from,to); 57 else if(mid<from)return query(mid+1,r,rt<<1|1,from,to); 58 else { 59 return query(l,mid,rt<<1,from,mid)+query(mid+1,r,rt<<1|1,mid+1,to); 60 61 } 62 } 63 int t,t1,t4; 64 long long t2,t3; 65 int main(){ 66 while(~scanf("%d%d",&n,&m)){ 67 memset(sum,0,sizeof(sum)); 68 memset(maxn,0,sizeof(maxn)); 69 build(1,n,1); 70 for(int i=1;i<=m;i++){ 71 scanf("%d%d",&t,&t1); 72 if(t==1){ 73 scanf("%d",&t4); 74 printf("%I64d ",query(1,n,1,t1,t4)); 75 } 76 else if(t==2){ 77 scanf("%d%I64d",&t4,&t2); 78 update(1,n,1,t1,t4,t2); 79 } 80 else{ 81 scanf("%I64d",&t2); 82 update2(1,n,1,t1,t2); 83 } 84 } 85 } 86 }