题解 P3157 【[CQOI2011]动态逆序对】

「QQ红包」

2018-01-18 21:35:49

Solution

my blog: redbag.pw 写的cdq分治。 考虑删除一个数$i​$ ,$i​$对答案的影响只有$i​$产生的贡献和$i​$对后面产生的影响 $x$:删除时间,$y$:位置,$z$:权值 求$i'$的逆序对:$x>x'$,$y<y'$,$z>z'$,求出一个答案$f_i$ 考虑 $i'$ 对后面的影响:$x>x'$,$y>y'$,$z<z'$,求出一个答案$g_i$ 对于最后没有删除的点,根据位置随便加一个删除时间。 然后就是三位偏序了。 求 $f_i$ ,按照删除时间从大到小排序,左边排 $z$ ,树状数组更 $y$ 求 $g_i$ ,按照删除时间从大到小排序,左边排 $y$ ,树状数组更 $z$ 最后扫一遍,更答案。 ```cpp #include<bits/stdc++.h> #define ll long long using namespace std; int qmax(int &x,int y) {if (x<y) x=y;} int qmin(int &x,int y) {if (x>y) x=y;} int read() { char s; int k=0,base=1; while((s=getchar())!='-'&&s!=EOF&&!(isdigit(s))); if(s=='-')base=-1,s=getchar(); while(isdigit(s)) { k=k*10+(s^'0'); s=getchar(); } return k*base; } void write(ll x) { if(x<0) { putchar('-'); write(-x); } else { if(x/10) write(x/10);putchar(x%10+'0'); } } const int maxn=1e5+100; const int maxm=5e4+100; int n,m; int b[maxn],c[maxn]; int t[maxn]; ll ans; struct node { int x,y,z;//x:删除的时间 y:pos z:值 int f,g; } a[maxn],A[maxn]; inline void xg(int x,int y) { while (x<=n) { *(t+x)+=y; x+=x&(-x); } } inline int qsum(int x) { int sum=0; while (x) { sum+=*(t+x); x-=x&(-x); } return sum; } bool cmp(node aa,node bb)//按照位置排序 { return aa.y<bb.y; } bool cmp1(node aa,node bb)//按照删除时间排 { return aa.x>bb.x; } bool cmp2(node aa,node bb) { return aa.x<bb.x; } void cdq(int x,int y) { if (x==y) return; int mid=(x+y)>>1; cdq(x,mid);cdq(mid+1,y); int l=x,r=mid+1,p=0; while (r<=y)//统答案 { while (l<=mid&&a[l].z>a[r].z) {xg(a[l].y,1);l++;} a[r].f+=qsum(a[r].y); r++; } for (int i=x;i<l;i++) xg(a[i].y,-1); l=x,r=mid+1,p=x-1;//归并 while (l<=mid&&r<=y) { if (a[l].z>a[r].z) A[++p]=a[l++]; else A[++p]=a[r++]; } while (l<=mid) A[++p]=a[l++]; while (r<=y) A[++p]=a[r++]; for (int i=x;i<=y;i++) a[i]=A[i]; } void CDQ(int x,int y) { if (x==y) return; int mid=(x+y)>>1; CDQ(x,mid);CDQ(mid+1,y); int l=x,r=mid+1,p=0; while (r<=y) { while (l<=mid&&a[l].y>a[r].y) {xg(a[l].z,1);l++;} a[r].g+=qsum(a[r].z); r++; } for (int i=x;i<l;i++) xg(a[i].z,-1);//memset太慢了,不如一个个清 l=x,r=mid+1,p=x-1;//按照y的大小合并 while (l<=mid&&r<=y) { if (a[l].y>a[r].y) A[++p]=a[l++]; else A[++p]=a[r++]; } while (l<=mid) A[++p]=a[l++]; while (r<=y) A[++p]=a[r++]; for (int i=x;i<=y;i++) a[i]=A[i]; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); n=read();m=read();//a数组初始按值排序 for (int i=1;i<=n;i++) { *(b+i)=read(); a[b[i]].y=i; a[b[i]].z=b[i]; ans+=i-1-qsum(b[i]); xg(b[i],1); } memset(t,0,sizeof(t)); for (int i=1;i<=m;i++) { *(c+i)=read(); a[c[i]].x=i; } sort(a+1,a+n+1,cmp); for (int i=1,j=m+1;i<=n;i++) { if (a[i].x==0) a[i].x=j++; } sort(a+1,a+n+1,cmp1); cdq(1,n);//求出f[i] sort(a+1,a+n+1,cmp1); CDQ(1,n);//求出g[i] sort(a+1,a+n+1,cmp2); for (int i=1;i<=m;i++) { write(ans); putchar('\n'); ans=ans-(ll)a[i].f-(ll)a[i].g; } return 0; } ```