BZOJ3295:[Cqoi2011]动态逆序对 (BIT套treap/CDQ分治+BIT)
来源:互联网 发布:linux宕机日志 编辑:程序博客网 时间:2024/06/07 14:36
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3295
题目分析:这题裸的树套树啊。我们先算出原序列的逆序对数量,当一个数被删除的时候,逆序对的减小量=此时在它前面的比它大的数的个数+此时在它后面的比它小的数的个数。于是我们用一个树状数组套平衡树就可以搞定了。
CODE(BIT+treap):
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;const int lg=20;const long long M=1000000009;const long long Times=998244353;typedef long long LL;struct Tnode{ int val,fix,Size; Tnode *lson,*rson; int Lsize() { return (lson? lson->Size:0); } int Rsize() { return (rson? rson->Size:0); } void Get_size() { Size=Lsize()+Rsize()+1; }} tree[maxn*lg];Tnode *bit[maxn];int cur=-1;LL seed,ans=0;int a[maxn];int p[maxn];int n,m;int Rand(){ seed=seed*Times%M; return (int)seed;}Tnode *New_node(int v){ cur++; tree[cur].val=v; tree[cur].fix=Rand(); tree[cur].Size=1; tree[cur].lson=tree[cur].rson=NULL; return tree+cur;}void Right_turn(Tnode *&P){ Tnode *W=P->lson; P->lson=W->rson; W->rson=P; P=W; P->rson->Get_size(); P->Get_size();}void Left_turn(Tnode *&P){ Tnode *W=P->rson; P->rson=W->lson; W->lson=P; P=W; P->lson->Get_size(); P->Get_size();}void Insert(Tnode *&P,int v){ if (!P) P=New_node(v); else { if ( v<P->val ) { Insert(P->lson,v); if ( P->lson->fix<P->fix ) Right_turn(P); } else { Insert(P->rson,v); if ( P->rson->fix<P->fix ) Left_turn(P); } P->Get_size(); }}void Add(int x,int v){ while (x<=n) { Insert(bit[x],v); x+=(x&(-x)); }}int Query(Tnode *P,int v){ if (!P) return 0; if ( P->val<v ) return P->Lsize()+1+Query(P->rson,v); return Query(P->lson,v);}int Sum(int x,int v,bool f){ int sum=0; while (x) { int temp=Query(bit[x],v); if ( f && bit[x] ) temp=bit[x]->Size-temp; sum+=temp; x-=(x&(-x)); } return sum;}void Delete(Tnode *&P,int v){ if ( P->val==v ) if ( !P->lson ) if ( !P->rson ) P=NULL; else P=P->rson; else if ( !P->rson ) P=P->lson; else if ( P->lson->fix<P->rson->fix ) Right_turn(P),Delete(P->rson,v),P->Get_size(); else Left_turn(P),Delete(P->lson,v),P->Get_size(); else if ( v<P->val ) Delete(P->lson,v),P->Get_size(); else Delete(P->rson,v),P->Get_size();}void Dec(int x,int v){ while (x<=n) { Delete(bit[x],v); x+=(x&(-x)); }}int main(){ freopen("3295.in","r",stdin); freopen("3295.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%d",&a[i]),p[ a[i] ]=i,bit[i]=NULL; seed=p[1]; for (int i=1; i<=n; i++) Add(i,a[i]),ans+=(long long)( Sum(i-1,a[i],1) ); for (int i=1; i<=m; i++) { printf("%lld\n",ans); int x; scanf("%d",&x); Dec(p[x],x); ans-=Sum(p[x]-1,x,1); ans-=( Sum(n,x,0)-Sum(p[x],x,0) ); } return 0;}
当然,我们也可以用CDQ分治。如果我们将此题的操作序列抽象出来,大概就是这样:QDQDQDQD,其中Q表示查询,D表示删数。我们记nx[i]为逆序对中有i这个值的逆序对数,则原数列的逆序对总数为
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=100100;const int maxm=maxn>>1;typedef long long LL;struct data{ int id; bool Left;} b[maxn];int work[maxn];LL num[maxn];int bit[maxn];LL nx[maxn];LL sum=0;int a[maxn];int p[maxn];int n,m;int Sum(int x){ int temp=0; while (x) { temp+=bit[x]; x-=(x&(-x)); } return temp;}void Add(int x,int v){ while (x<=n) { bit[x]+=v; x+=(x&(-x)); }}bool Comp1(data x,data y){ return p[ work[ x.id ] ]<p[ work[ y.id ] ];}bool Comp2(data x,data y){ return p[ work[ x.id ] ]>p[ work[ y.id ] ];}void CDQ(int L,int R){ if (L==R) return; int mid=(L+R)>>1; CDQ(L,mid); int temp=0; LL dec=0; for (int i=L; i<=mid; i++) if (work[i]) { temp++; b[temp].id=i; b[temp].Left=true; dec+=num[i]; } for (int i=mid+1; i<=R; i++) if (work[i]) { temp++; b[temp].id=i; b[temp].Left=false; } else num[i]-=dec; sort(b+1,b+temp+1,Comp1); int k=0; for (int i=1; i<=temp; i++) { int j=b[i].id; if (!b[i].Left) num[j]-=(k-Sum(work[j])); else k++,Add(work[j],1); } for (int i=1; i<=temp; i++) if (b[i].Left) Add(work[ b[i].id ],-1); sort(b+1,b+temp+1,Comp2); for (int i=1; i<=temp; i++) { int j=b[i].id; if (!b[i].Left) num[j]-=Sum(work[j]-1); else Add(work[j],1); } for (int i=1; i<=temp; i++) if (b[i].Left) Add(work[ b[i].id ],-1); CDQ(mid+1,R);}int main(){ freopen("3295.in","r",stdin); freopen("3295.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) { scanf("%d",&a[i]); p[ a[i] ]=i; nx[i]=(i-1)-Sum(a[i]); Add(a[i],1); } for (int i=1; i<=n; i++) bit[i]=0; for (int i=n; i>=1; i--) { nx[i]+=Sum(a[i]-1); Add(a[i],1); } for (int i=1; i<=n; i++) bit[i]=0,sum+=nx[i]; sum>>=1; for (int i=1; i<=m; i++) { int x=(i<<1)-1; num[x]=sum; x++; scanf("%d",&work[x]); num[x]=nx[ p[ work[x] ] ]; } CDQ(1,m<<1); for (int i=1; i<(m<<1); i+=2) printf("%lld\n",num[i]); return 0;}
阅读全文
1 0
- BZOJ3295:[Cqoi2011]动态逆序对 (BIT套treap/CDQ分治+BIT)
- [BZOJ3295] [Cqoi2011]动态逆序对 && CDQ分治
- [BZOJ3295][Cqoi2011]动态逆序对(树状数组套线段树||cdq分治)
- BZOJ3295: [Cqoi2011]动态逆序对(CDQ分治)
- bzoj3295 [Cqoi2011]动态逆序对(CDQ分治)
- 【BZOJ3295】动态逆序对,CDQ分治/BIT套权值线段树
- [BZOJ3295] [Cqoi2011]动态逆序对 (树套树)or(CDQ分治)
- CDQ分治——BZOJ3295/Luogu3157 [CQOI2011]动态逆序对
- [BZOJ3295][CQOI2011]动态逆序对-CDQ分治+树状数组
- bzoj3295[Cqoi2011]动态逆序对(cdq分治||可持久化线段树)
- 【BZOJ3295】动态逆序对(CQOI2011)-CDQ分治:三维偏序
- bzoj3295[Cqoi2011]动态逆序对 cdq分治(树套树/主席树)
- 整体二分&CDQ分治:[BZOJ2527][POI2011] meteors [BZOJ3295][CQOI2011] 动态逆序对
- 【cdq分治】[HYSBZ/BZOJ3295]动态逆序对
- 【bzoj3295】动态逆序对 CDQ分治
- [BZOJ3295]动态逆序对CDQ分治
- 【CDQ分治】[CQOI2011][NKOJ2041]动态逆序对
- 3295: [Cqoi2011]动态逆序对 CDQ分治
- SSL P2133 腾讯大战360
- Ubuntu界面美化
- 主动上报电话信息流程分析
- tomcat启动脚本
- 26. Remove Duplicates from Sorted Array
- BZOJ3295:[Cqoi2011]动态逆序对 (BIT套treap/CDQ分治+BIT)
- 二分搜索poj106
- IntelliJ IDEA +Maven 创建Scala项目涉及的问题以及解决方案
- Android WebView与 JS 交互方式
- 金蝶K3 SQL报表系列-委外核销检查表
- 【JavaScript】parseInt()函数
- vue之vue-router vuex学习笔记
- 51 nod 1072 威佐夫博弈
- HDU-2017 多校训练赛5-1001-Rikka with Candies