[CQOI2011]动态逆序对(主席树,树状数组)
Posted hsez-cyx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2011]动态逆序对(主席树,树状数组)相关的知识,希望对你有一定的参考价值。
题目描述
对于序列 aa,它的逆序对数定义为集合
{(i,j)| i<j wedge a_i > a_j }{(i,j)∣i<j∧ai?>aj?}
中的元素个数。
现在给出 1sim n1∼n 的一个排列,按照某种顺序依次删除 mm 个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
输入格式
第一行包含两个整数 nn 和 mm,即初始元素的个数和删除的元素个数。
以下 nn 行,每行包含一个 1 sim n1∼n 之间的正整数,即初始排列。
接下来 mm 行,每行一个正整数,依次为每次删除的元素。
输出格式
输出包含 mm 行,依次为删除每个元素之前,逆序对的个数。
Solution
(其实我觉得更像是一个动态开点线段树啊,为什么归到主席树里???等我学了那东西再回来看看吧)
首先用树状数组求逆序对(正着来一次反着来一次)
a1[ d[ i ] ]:编号在 i 前且值比 d[ i ]小的个数
a2[ d[ i ] ]:编号在 i 后且值比 d[ i ] 的值大的个数
然后每次删去一个数t减去a1[ t ]+a2[ t ]
聪明的你肯定马上发现减多了吧(正反都会减一次)
这时用主席树维护已经删去的数里跟它构成逆序对的个数
即删去 t 时比它所在编号(re[ t ])大的编号的权值线段树里 t 加1(自然语言好无力。。。)
为了减小复杂度此处用树状数组优化
Code
#include <cstdio> #include <cstdlib> #include <cstring> #define ll long long using namespace std; const int N=1e5+10; ll s_t[N],a1[N],a2[N],sum; int n,m,t,d[N],re[N]; int lowbit(int x) { return x&(-x); } ll s_get(int x,int y) { ll ans=0; for(;y;y-=lowbit(y)) ans+=s_t[y]; for(;x;x-=lowbit(x)) ans-=s_t[x]; return ans; } void s_add(int x) { for(;x<=n;x+=lowbit(x)) s_t[x]++; } int rt[N],tot; struct node { int lc,rc,v; }f[N*60]; void z_add(int &g,int l,int r,int pos) { if(!g) g=++tot; f[g].v++; if(l==r) return ; int mid=(l+r)>>1; if(pos<=mid) z_add(f[g].lc,l,mid,pos); else z_add(f[g].rc,mid+1,r,pos); } ll z_get(int g,int l,int r,int x,int y) { if(x>y || g==0) return 0; if(l>=x && r<=y) return f[g].v; int mid=(l+r)>>1; if(y<=mid) return z_get(f[g].lc,l,mid,x,y); else if(x>mid) return z_get(f[g].rc,mid+1,r,x,y); else return z_get(f[g].lc,l,mid,x,mid)+z_get(f[g].rc,mid+1,r,mid+1,y); } ll Get(int x,int y,int l,int r) { if(l>r) return 0; ll ans=0; for(;y;y-=lowbit(y)) ans+=z_get(rt[y],1,n,l,r); for(;x;x-=lowbit(x)) ans-=z_get(rt[x],1,n,l,r); return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&d[i]); re[d[i]]=i; a1[d[i]]=s_get(d[i],n); s_add(d[i]),sum+=a1[d[i]]; } memset(s_t,0,sizeof(s_t)); for(int i=n;i;i--) a2[d[i]]=s_get(0,d[i]),s_add(d[i]); while(m--) { scanf("%d",&t); printf("%lld ",sum); sum-=a1[t]+a2[t]-Get(0,re[t],t+1,n)-Get(re[t],n,1,t-1); for(int i=re[t];i<=n;i+=lowbit(i)) z_add(rt[i],1,n,t); } return 0; }
以上是关于[CQOI2011]动态逆序对(主席树,树状数组)的主要内容,如果未能解决你的问题,请参考以下文章