题目:
【题目描述】
现有给定一个序列a_0,a_1,.....a_(n-1)共n项以及m个操作。操作分成以下三类:
0: 将区间[l,r]中的数加上一个值x
1: 将区间[l,r]中的数乘上-1
2: 询问区间[l,r]中的数的绝对值之和
编程实现以上操作。
【输入格式】
第一行两个数n,m,分别表示序列的长度和操作的个数
第二行n个数,第i个数表示a_(i-1)
第三至m+2行,每行采取下列形式之一:
0 l r x (表示第0种操作)
1 l r (表示第1种操作)
2 l r (表示第2种操作)
l,r,x意义如题目描述中所述。
【输出格式】
共k行(其中k是第2种操作的个数),第i行有且仅有一个数,表示第i次第2种操作的答案。
【样例输入】
4 4
-2 -1 0 1
2 0 3
1 1 3
0 0 1 2
2 0 2
【样例输出】
4
3
【时空限制与数据约束】
时间:3s 空间:256MB
对于40%的数据,n,m<=10000
对于100%的数据,n,m<=100000
数据保证所有时刻序列中的数的绝对值总和不会超过64位有符号整形范围。
题解:
乍一看以为是水题……写了一个多小时Seg套Splay发现调不出来……oh,fxxk!然后就mengbier了= =。
zyf大佬使用吉司机线段树思想?(这是什么?)
题解是分块233,真是妙啊。
当时一心想怎么用线段树维护233,没有考虑用分块/莫队……emmmm,真是
改起来也十分不方便……真的很naive……
考虑如何维护,因为*-1实际上绝对值不会改变只是每个值从$now[x]=a[x]+add[bel[x]]$改变为$-now[x]$,但以后给该元素+add就会变为-add,画个图就明白了,这样搞定了操作0。
然后对于*-1的维护(当然是两边的啦),假设这个块被标记了奇数次-1,那么实际每个数值均为当前记录的值的相反数,但是我们又有一部分变为了偶数次-1,发现假设块的add不变,我们直接给这几个值*-1是错的,(列列式子就明白),那么处理这个问题有两种方式,1是块里每个元素+add再乘-1,然后把add清空,再把部分修改的值*-1,重建这个块,2是给修改元素+add*2,再*-1。第一个很好理解,第二个化化式子就明白了。
当然由于维护块内答案需要二分,所以要把块设的小一点。
代码:
1 #include "bits/stdc++.h" 2 3 using namespace std; 4 5 typedef long long ll; 6 7 inline int read(){ 8 int s=0,k=1;char ch=getchar(); 9 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); 10 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); 11 return s*k; 12 } 13 14 15 inline ll readll(){ 16 ll s=0,k=1;char ch=getchar(); 17 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); 18 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); 19 return s*k; 20 } 21 22 const int N=1e5+10; 23 24 25 ll a[N],ans[N],mo[N],b[1005][202],sum[1005][205]; 26 27 bool rev[N]; 28 29 int n,m,leth,bel[N],vis[N],L[N],R[N]; 30 31 inline void build(int op,int l,int r){ 32 int i; 33 memcpy(b[op],a+l,sizeof b[op]); 34 sort(b[op],b[op]+r-l+1); 35 memcpy(sum[op],b[op],sizeof sum[op]); 36 ans[op]=abs(b[op][0]+mo[op]); 37 for (i=1;i+l<=r;++i) 38 sum[op][i]+=sum[op][i-1],ans[op]+=abs(b[op][i]+mo[op]); 39 vis[op]=0; 40 } 41 42 inline void update(int l,int r,int lk,int rk,ll add){ 43 int i; 44 if(lk==rk) { 45 if(rev[lk]) add=-add; 46 for (i=l;i<=r;++i) a[i]+=add; 47 build(lk,L[lk],R[lk]); 48 }else { 49 ll pl; 50 if(rev[lk]) pl=-add;else pl=add; 51 for (i=l;i<=R[lk];++i) a[i]+=pl; 52 build(lk,L[lk],R[lk]); 53 if(rev[rk]) pl=-add;else pl=add; 54 for (i=L[rk];i<=r;++i) a[i]+=pl; 55 build(rk,L[rk],R[rk]); 56 for (i=lk+1;i<rk;++i) mo[i]+=(rev[i]?-add:add),vis[i]=true; 57 } 58 } 59 60 inline void sigh(int l,int r,int lk,int rk){ 61 int i; 62 if(lk==rk) { 63 for (i=l;i<=r;++i) a[i]=-(a[i]+2*mo[lk]); 64 build(lk,L[lk],R[lk]); 65 }else { 66 for (i=l;i<=R[lk];++i) a[i]=-(a[i]+2*mo[lk]); 67 build(lk,L[lk],R[lk]); 68 for (i=L[rk];i<=r;++i) a[i]=-(a[i]+2*mo[rk]); 69 build(rk,L[rk],R[rk]); 70 for (i=lk+1;i<rk;++i) rev[i]^=1; 71 } 72 } 73 74 inline ll query (int op){ 75 int l=-1,r=R[op]-L[op]+1,mid; 76 while(l+1<r){ 77 int mid=l+r>>1; 78 if(b[op][mid]+mo[op]>=0) r=mid; 79 else l=mid; 80 } 81 vis[op]=0; 82 ans[op]=(sum[op][R[op]-L[op]]-sum[op][l])+mo[op]*(R[op]-l-L[op]) 83 -((l+1)*mo[op]+sum[op][l]); 84 return ans[op]; 85 } 86 87 inline ll query (int l,int r,int lk,int rk){ 88 ll ret=0;int i; 89 if(lk==rk) 90 for (i=l;i<=r;++i) ret+=abs(a[i]+mo[lk]); 91 else { 92 for (i=l;i<=R[lk];++i) ret+=abs(a[i]+mo[lk]); 93 for (i=L[rk];i<=r;++i) ret+=abs(a[i]+mo[rk]); 94 for (i=lk+1;i<rk;++i) 95 if(!vis[i]) ret+=ans[i]; 96 else ret+=query(i); 97 } 98 return ret; 99 } 100 101 int main(){ 102 scanf("%d%d",&n,&m);leth=100; 103 for (int i=1;i<=n;++i){ 104 a[i]=readll(); 105 bel[i]=(i-1)/leth; 106 L[bel[i]]?0:L[bel[i]]=i; 107 R[bel[i]]=i; 108 b[bel[i]][i-bel[i]*leth-1]=a[i]; 109 } 110 register int i,j; 111 112 for (i=0;i<=bel[n];++i){ 113 sort(b[i],b[i]+R[i]-L[i]+1); 114 memcpy(sum[i],b[i],sizeof (sum[i])); 115 ans[i]=abs(b[i][0]); 116 for (j=1;j+L[i]<=R[i];++j) sum[i][j]+=sum[i][j-1],ans[i]+=abs(b[i][j]); 117 } 118 ll x; 119 int type,l,r; 120 int tot=0; 121 while (m--){ 122 type=read(),l=read()+1,r=read()+1; 123 if(!type) 124 x=read(), update(l,r,bel[l],bel[r],x); 125 else if(type&1) sigh(l,r,bel[l],bel[r]); 126 else printf("%lld\n",query(l,r,bel[l],bel[r])); 127 } 128 }