标签:else iostream 正整数 turn code 树状 pen 效率 stdin
cdq分治妙啊
(被改过题面的)原题:
dydxh所出的题目是这样的:
有一个N*N矩阵,给出一系列的修改和询问,修改是这样的:将(x,y)中的数字加上k,而询问是这样的:求(x1,y1)到(x2,y2)这个子矩阵内所有数字的和。
虽然这么高级的数据结构题mzx这种菜逼当然不会,但是由于dydxh给mzx留了一条没有强制在线的生路,所以mzx决定挑战一下这道题。
1<=N<=500000,操作数不超过200000个,操作1中的k为正整数,且不超过2000
思路很妙,知道为什么要这样做但是感觉考场上想不出来QAQ
首先询问容斥成4个前缀和问题,设时间轴为z,问题就变成询问z<qz,x<qx,y<qy里面的数总和是多少
然后就跟数星星很像了,排序x,这样右边的x保证比左边的x大,cdq分治z,树状数组y
看网上的做法和我之前想的有点不一样,我之前想的是想归并排序那样从将右边的队头和左边的队头比较,小的出队,先递归,再计算
网上比较多的做法是,先计算,左边的修改给右边的查询贡献,然后把时间轴<=mid的放到mid左边,>mid的放到右边,再递归下一层
感觉第二种对于我来说更好理解吧,比较贴合cdq分治的本质,现在还不能理解这两种写法的联系
听闵神说递归的效率非常低?我和山神的递归2.2s,闵神迭代0.4s……
还需要想一下迭代的写法啊
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 int read(){int z=0,mark=1; char ch=getchar(); 10 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)mark=-1; ch=getchar();} 11 while(ch>=‘0‘&&ch<=‘9‘){z=(z<<3)+(z<<1)+ch-‘0‘; ch=getchar();} 12 return z*mark; 13 } 14 struct cdd{int x,y,z,v,mk;}a[810000]; int tp=0; 15 int n; 16 int e[510000],lbt[510000]; 17 cdd q[810000]; int hd=0; 18 int ans[210000]; 19 int t=0; 20 void gtlbt(){for(int i=1;i<=500000;++i)lbt[i]=i&-i;} 21 void mdf(int x,int y){while(x<=n) e[x]+=y,x+=lbt[x];} 22 int qr(int x){int bwl=0; while(x) bwl+=e[x],x-=lbt[x]; return bwl;} 23 //int qr(int x){int bwl=0; while(x) bwl+=e[x],x-=lbt[x];} 24 void dfs(int l,int r){ 25 if(l==r) return ; 26 int md=(l+r)>>1; 27 for(int i=l;i<=r;++i){ 28 if(!a[i].mk && a[i].z<=md) mdf(a[i].y,a[i].v); 29 else if(a[i].mk && a[i].z>md) 30 ans[a[i].v]+=a[i].mk*qr(a[i].y); 31 } 32 for(int i=l;i<=r;++i)if(!a[i].mk && a[i].z<=md) mdf(a[i].y,-a[i].v); 33 int t1=l,t2=md+1; 34 for(int i=l;i<=r;++i) q[(a[i].z<=md?t1:t2)++]=a[i]; 35 for(int i=l;i<=r;++i) a[i]=q[i]; 36 dfs(l,md),dfs(md+1,r); 37 } 38 bool cmp(cdd x,cdd y){return (x.x==y.x)?((x.z==y.z)?x.y<y.y:x.z<y.z):x.x<y.x;} 39 int main(){//freopen("ddd.in","r",stdin); 40 gtlbt(); 41 cin>>n; 42 int mk,x,y,z,v; 43 while((mk=read())!=3){ 44 if(mk==1) a[++tp].mk=0,a[tp].x=read(),a[tp].y=read(),a[tp].v=read(),a[tp].z=tp; 45 else{ 46 x=read(),y=read(),z=read(),v=read(); 47 a[++tp].mk=1,a[tp].x=z,a[tp].y=v,a[tp].z=tp,a[tp].v=++t; 48 a[++tp].mk=1,a[tp].x=x-1,a[tp].y=y-1,a[tp].z=tp,a[tp].v=t; 49 a[++tp].mk=-1,a[tp].x=z,a[tp].y=y-1,a[tp].z=tp,a[tp].v=t; 50 a[++tp].mk=-1,a[tp].x=x-1,a[tp].y=v,a[tp].z=tp,a[tp].v=t; 51 } 52 } 53 sort(a+1,a+tp+1,cmp); 54 dfs(1,tp); 55 for(int i=1;i<=t;++i) printf("%d\n",ans[i]); 56 return 0; 57 }
标签:else iostream 正整数 turn code 树状 pen 效率 stdin
原文地址:http://www.cnblogs.com/JSL2018/p/6412232.html