首页 > 代码库 > [bzoj3295][Cqoi2011][动态逆序对] (树套树)
[bzoj3295][Cqoi2011][动态逆序对] (树套树)
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4153425142
Sample Output
5221
样例解释
(1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。
HINT
N<=100000 M<=50000
Solution
1.动态主席树(树状数组套主席树)
可以很简单地得出每个点的贡献,考虑怎样不重复计算就行了。去重用动态主席树实现
#include<stdio.h>#include<string.h>#define LL long long#define RG register#define inline __inline__ __attribute__((always_inline))#define lbt(x) ((x)&(-x))#define mid ((x>>1)+(y>>1)+(x&y&1))#define N 100010namespace BIT{ int c[N]; inline void clr(){ memset(c,0,sizeof(c)); } inline void add(RG int x,RG int n){ for(;x<=n;x+=lbt(x)) c[x]++; } inline int sum(RG int x){ RG int res=0; for(;x;x-=lbt(x)) res+=c[x]; return res; }}LL ans;int n,m,num[N],pos[N],left[N],right[N];namespace FST{ int sum[N<<6],ls[N<<6],rs[N<<6],rt[N],top,f[50],g[50]; void modify(int &pr,RG int x,RG int y,RG int pos){ if(!pr)pr=++top; sum[pr]++; if(x<y) pos<=mid?modify(ls[pr],x,mid,pos): modify(rs[pr],mid+1,y,pos); } inline void Back_d(RG int x,RG int y){ f[0]=g[0]=0; for(;x;x-=lbt(x)) f[++f[0]]=rt[x]; for(;y;y-=lbt(y)) g[++g[0]]=rt[y]; } int Query_l(RG int x,RG int y,RG int pos){ if(x==y)return 0; if(pos<=mid){ RG int tmp=0; for(RG int i=1;i<=f[0];i++) tmp-=sum[rs[f[i]]], f[i]=ls[f[i]]; for(RG int i=1;i<=g[0];i++) tmp+=sum[rs[g[i]]], g[i]=ls[g[i]]; return tmp+Query_l(x,mid,pos); } for(RG int i=1;i<=f[0];i++) f[i]=rs[f[i]]; for(RG int i=1;i<=g[0];i++) g[i]=rs[g[i]]; return Query_l(mid+1,y,pos); } int Query_r(RG int x,RG int y,RG int pos){ if(x==y)return 0; if(pos<=mid){ for(RG int i=1;i<=f[0];i++) f[i]=ls[f[i]]; for(RG int i=1;i<=g[0];i++) g[i]=ls[g[i]]; return Query_r(x,mid,pos); } RG int tmp=0; for(RG int i=1;i<=f[0];i++) tmp-=sum[ls[f[i]]], f[i]=rs[f[i]]; for(RG int i=1;i<=g[0];i++) tmp+=sum[ls[g[i]]], g[i]=rs[g[i]]; return tmp+Query_r(mid+1,y,pos); } void main(RG int p){ ans-=left[p]+right[p]; Back_d(0,p-1); ans+=Query_l(1,n,num[p]); Back_d(p,n); ans+=Query_r(1,n,num[p]); for(RG int i=p;i<=n;i+=lbt(i)) modify(rt[i],1,n,num[p]); }}int main(){ scanf("%d%d",&n,&m); BIT::clr(); for(RG int i=1;i<=n;i++){ scanf("%d",&num[i]); pos[num[i]]=i; left[i]=i-1-BIT::sum(num[i]-1); ans+=left[i]; BIT::add(num[i],n); } BIT::clr(); for(RG int i=n;i;i--){ right[i]=BIT::sum(num[i]-1); BIT::add(num[i],n); } while(m--){ RG int x; scanf("%d",&x); printf("%lld\n",ans); FST::main(pos[x]); } return 0;}
[bzoj3295][Cqoi2011][动态逆序对] (树套树)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。