洛谷P1393 动态逆序对(CDQ分治)
2018-08-12 08:22
274 查看
传送门
[b]题解[/b]
听别人说这是洛谷用户的双倍经验啊……然而根本没有感觉到……因为另外的那题我是用树状数组套主席树做的……而且莫名其妙感觉那种方法思路更清晰(虽然码量稍稍大了那么一点点)……感谢Candy大佬教会了我CDQ的动态逆序对……莫名其妙1A了……
因为是删除,所以可以看成倒着加入。而且没规定都在$n$以内,所以要离散。我们把每一个位置都表示成一个三元组$(t,x,y)$,其中$t$表示加入的时间,$x$表示在原数组中的位置,$y$表示离散之后的值。求逆序对,就代表求有多少个三元组满足$t'<t,x'<x,y'>y$或$t'<t,x'>x,y'<y$。我们可以先把时间这一维排序,然后CDQ的时候顺便排好$x$这一维,$y$这一维用树状数组求解。因为要找两种,所以CDQ的时候要两个分别找,这一部分的细节可以参考代码
[b]题解[/b]
听别人说这是洛谷用户的双倍经验啊……然而根本没有感觉到……因为另外的那题我是用树状数组套主席树做的……而且莫名其妙感觉那种方法思路更清晰(虽然码量稍稍大了那么一点点)……感谢Candy大佬教会了我CDQ的动态逆序对……莫名其妙1A了……
因为是删除,所以可以看成倒着加入。而且没规定都在$n$以内,所以要离散。我们把每一个位置都表示成一个三元组$(t,x,y)$,其中$t$表示加入的时间,$x$表示在原数组中的位置,$y$表示离散之后的值。求逆序对,就代表求有多少个三元组满足$t'<t,x'<x,y'>y$或$t'<t,x'>x,y'<y$。我们可以先把时间这一维排序,然后CDQ的时候顺便排好$x$这一维,$y$这一维用树状数组求解。因为要找两种,所以CDQ的时候要两个分别找,这一部分的细节可以参考代码
//minamoto #include<iostream> #include<cstdio> #include<algorithm> #define ll long long using namespace std; #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) char buf[1<<21],*p1=buf,*p2=buf; inline int read(){ #define num ch-'0' char ch;bool flag=0;int res; while(!isdigit(ch=getc())) (ch=='-')&&(flag=true); for(res=num;isdigit(ch=getc());res=res*10+num); (flag)&&(res=-res); #undef num return res; } char sr[1<<21],z[20];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(ll x){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=' '; } const int N=4e4+5; int n,m,c ,ty,yy ; inline void add(int x,int val){ for(;x<=ty;x+=x&-x) c[x]+=val; } inline int query(int x){ int res=0; for(;x;x-=x&-x) res+=c[x]; return res; } inline void clear(int x){ for(;x<=ty;x+=x&-x) if(c[x]) c[x]=0;else break; } struct node{ int t,x,y; node(){} node(int t,int x,int y):t(t),x(x),y(y){} bool operator <(const node &b)const {return x==b.x?y<b.y:x<b.x;} }a ,p ; inline bool cmptime(const node &a,const node &b){ return a.t==b.t?a.x<b.x:a.t<b.t; } ll ans ; void CDQ(int l,int r){ if(l==r) return; int mid=l+r>>1; CDQ(l,mid),CDQ(mid+1,r); for(int i=l,j=l,k=mid+1;i<=r;){ if(k>r||(j<=mid&&a[j]<a[k])) add(a[j].y,1),p[i++]=a[j++]; else ans[a[k].t]+=query(n)-query(a[k].y),p[i++]=a[k++]; } for(int i=l;i<=mid;++i) clear(a[i].y); for(int i=l;i<=r;++i) a[i]=p[i]; for(int i=r;i>=l;--i){ if(a[i].t<=mid) add(a[i].y,1); else ans[a[i].t]+=query(a[i].y-1); } for(int i=l;i<=r;++i) clear(a[i].y); } int main(){ //freopen("testdata.in","r",stdin); n=read(),m=read(); for(int i=1;i<=n;++i){ yy[i]=read(),a[i]=node(0,i,yy[i]); } sort(yy+1,yy+1+n); ty=unique(yy+1,yy+1+n)-yy-1; for(int i=1;i<=n;++i) a[i].y=lower_bound(yy+1,yy+1+ty,a[i].y)-yy; int Time=n; for(int i=1;i<=m;++i){ int k=read();a[k].t=Time--; } for(int i=1;i<=n;++i) if(!a[i].t) a[i].t=Time--; sort(a+1,a+1+n,cmptime); CDQ(1,n); for(int i=1;i<=n;++i) ans[i]+=ans[i-1]; for(int i=n;i>=n-m;--i) print(ans[i]); Ot(); return 0; }
相关文章推荐
- bzoj3295 [Cqoi2011]动态逆序对(CDQ分治)
- bzoj3295[Cqoi2011]动态逆序对(cdq分治||可持久化线段树)
- [BZOJ3295][Cqoi2011]动态逆序对(树状数组套线段树||cdq分治)
- [BZOJ3295][Cqoi2011]动态逆序对(CDQ分治||树套树)
- 【Bzoj 3295】 动态逆序对(树套树|CDQ分治)
- BZOJ 3295 动态逆序对(CDQ分治)
- [BZOJ3295] [Cqoi2011]动态逆序对 (树套树)or(CDQ分治)
- 【BZOJ3295】动态逆序对(CQOI2011)-CDQ分治:三维偏序
- bzoj 3295 [Cqoi2011]动态逆序对(cdq分治,BIT)
- 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治
- BZOJ 3295: [Cqoi2011]动态逆序对 CDQ分治
- 【CDQ分治】BZOJ3295 [Cqoi2011]动态逆序对
- 【bzoj3295】动态逆序对 CDQ分治
- BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)
- BZOJ 3295: [Cqoi2011]动态逆序对 [CDQ分治]
- hdu 6183 Color it(动态线段树,cdq分治)
- 3295: [Cqoi2011]动态逆序对 CDQ分治
- [bzoj] 3295 动态逆序对 || CDQ分治
- 整体二分&CDQ分治:[BZOJ2527][POI2011] meteors [BZOJ3295][CQOI2011] 动态逆序对
- CQOI2011动态逆序对--cdq分治