题解-P3157 [CQOI2011]动态逆序对
Posted wanghaoyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解-P3157 [CQOI2011]动态逆序对相关的知识,希望对你有一定的参考价值。
树状数组套线段树,用动态开点线段树。此类就这一题放在这吧。
程序写的太丑了,不要介意。
#include<iostream> #include<cstdio> using namespace std; typedef long long i64; const int N=1e5+5; const int S=1e7+7; int a[N],p[N]; int q[N]; bool b[N]; int r[N]; int cnt,x[S],c[S][2]; i64 ans[N]; void add(int &v,int xx,int l,int r) if(!v) v=++cnt; ++x[v]; if(l==r) return; int mid=(l+r)>>1; if(xx<=mid) add(c[v][0],xx,l,mid); else add(c[v][1],xx,mid+1,r); int ct(int &v,int xx,int yy,int l,int r) if(!v) return 0; if(xx<=l&&r<=yy) return x[v]; int mid=(l+r)>>1,s=0; if(xx<=mid) s+=ct(c[v][0],xx,yy,l,mid); if(mid<yy) s+=ct(c[v][1],xx,yy,mid+1,r); return s; int n; void ins(int p,int a) int i; for(i=p;i<=n;i+=-i&i) add(r[i],a,1,n); int clc(int p,int a) int i,s=0; for(i=p;i;i-=-i&i) s+=ct(r[i],a+1,n,1,n); for(i=n;i;i-=-i&i) s+=ct(r[i],1,a-1,1,n); for(i=p;i;i-=-i&i) s-=ct(r[i],1,a-1,1,n); return s; int main() int m,i; i64 s=0; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&a[i]); p[a[i]]=i; for(i=1;i<=m;i++) scanf("%d",&q[i]); b[p[q[i]]]=1; for(i=1;i<=n;i++) if(!b[i]) s+=clc(i,a[i]); ins(i,a[i]); for(i=m;i;i--) s+=clc(p[q[i]],q[i]); ins(p[q[i]],q[i]); ans[i]=s; for(i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0;
用cdq分治更好。
#include<iostream> #include<cstdio> using namespace std; typedef long long i64; const int N=1e5+5; i64 ans[N]; struct inf int p,t; i64 *q; x[N],y[N]; int n; int bt[N],mt[N]; int a[N],q[N]; void add(int t) for(;t<=n;t+=t&-t) ++bt[t]; void dec(int t) for(;t<=n;t+=t&-t) --bt[t]; int ask(int t) int s=0; for(;t;t-=t&-t) s+=bt[t]; return s; void _add(int t) for(;t<=n;t+=t&-t) ++mt[t]; void _dec(int t) for(;t<=n;t+=t&-t) --mt[t]; int _ask(int t) int s=0; for(;t;t-=t&-t) s+=mt[t]; return s; void cdqdc(int l,int r) if(l==r) return; int mid=(l+r)>>1; cdqdc(l,mid); cdqdc(mid+1,r); int i,j,p; for(i=l;i<=mid;i++) _add(x[i].t); for(i=l,j=mid+1,p=l;i<=mid||j<=r;p++) if(j>r||i<=mid&&x[i].p<x[j].p) *x[i].q+=ask(x[i].t); _dec(x[i].t); y[p]=x[i++]; else add(x[j].t); *x[j].q+=_ask(x[j].t); y[p]=x[j++]; for(j=mid+1;j<=r;j++) dec(x[j].t); for(p=l;p<=r;p++) x[p]=y[p]; int main() int m,i; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&a[i]); x[a[i]].p=i; x[a[i]].q=ans+m+1; for(i=1;i<=m;i++) scanf("%d",&q[i]); x[q[i]].t=n-i+1; x[q[i]].q=ans+i; int s=0; for(i=1;i<=n;i++) if(!x[i].t) x[i].t=++s; cdqdc(1,n); for(i=m;i;i--) ans[i]+=ans[i+1]; for(i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0;
以上是关于题解-P3157 [CQOI2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治
[Luogu P3157][CQOI2011]动态逆序对 (树套树)