[CQOI2011]动态逆序对
Posted 殇雪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2011]动态逆序对相关的知识,希望对你有一定的参考价值。
我们发现这道题可以用树状数组套权值线段树(主席树的一些优化)
(不会点这里) 我感觉我这样写下去朴素的主席树要不会写了。
我们发现一个点对答案的贡献有两部份,在其之前比其大的,在其之后比他小的。
我们每次删除一个点,把其对答案的贡献减去就好了。
我们考虑一下这样所费的空间,我们知道删除时是按原路径遍历,不会加空间。我们只考虑加点的空间开销。我们每次加一个点,期望我们访问log n个线段树,每个线段树log n个点,那么就是O(nlog n^2)的空间复杂度。5W*16*16=1280W?事实证明是不到的,因为我们不是每次都会开出logN^2个点。反正能开多大就开多大吧。
就酱紫。
#include<bits/stdc++.h> #define N 8500007 #define M 100007 #define Mid (l+r>>1) #define L(x) (x&-x) #define LL long long using namespace std; int siz[N],ls[N],rs[N],si,n,tot,ne[M],m,X,a[M],n2[M],n3[M],to1; LL ans; #define sight(c) (\'0\'<=c&&c<=\'9\') inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(LL x){if (x<10) {putchar(\'0\'+x); return;} write(x/10); putchar(\'0\'+x%10);} inline void writeln(LL x){ if (x<0) putchar(\'-\'),x*=-1; write(x); putchar(\'\\n\'); } void ins(int l,int r,int no,int q,int dla){ siz[no]+=dla; if (l==r) return; if (Mid>=q) {if (!ls[no]) ls[no]=++si;ins(l,Mid,ls[no],q,dla);} else {if (!rs[no]) rs[no]=++si;ins(Mid+1,r,rs[no],q,dla);} } void add(int x,int i,int dla){for (;x<=n;x+=L(x)) ins(1,n,x,i,dla);} int ask(int l,int r,int q){ if (l==r) return 0; if (Mid<q) { for (int i=1;i<=tot;i++) ne[i]=rs[ne[i]]; return ask(Mid+1,r,q); } int sum=0; for (int i=1;i<=tot;i++) sum+=siz[rs[ne[i]]],ne[i]=ls[ne[i]]; return sum+ask(l,Mid,q); } int Ask(int l,int r,int q){ if (l==r) return 0; if (q<=Mid) { for (int i=1;i<=tot;i++) n2[i]=ls[n2[i]]; for (int i=1;i<=to1;i++) n3[i]=ls[n3[i]]; return Ask(l,Mid,q); } LL sum=0; for (int i=1;i<=tot;i++) sum-=siz[ls[n2[i]]],n2[i]=rs[n2[i]]; for (int i=1;i<=to1;i++) sum+=siz[ls[n3[i]]],n3[i]=rs[n3[i]]; return sum+Ask(Mid+1,r,q); } int query(int r,int val){ for (tot=0;r;r-=L(r)) ne[++tot]=r; return ask(1,n,val); } int Query(int r,int val){ int y=n; for (tot=0;r;r-=L(r)) n2[++tot]=r; for (to1=0;y;y-=L(y)) n3[++to1]=y; return Ask(1,n,val); } int main () { freopen("inverse.in","r",stdin); freopen("inverse.out","w",stdout); read(n); read(m); si=n; for (int i=1;i<=n;i++) read(X),add(i,X,1),a[X]=i; for (int i=1;i<=n;i++) ans+=query(a[i],i); while (m--) { writeln(ans);read(X); ans-=Query(a[X],X)+query(a[X],X); add(a[X],X,-1); }return 0; }
以上是关于[CQOI2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章