【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=3295
【题意】
n个元素依次删除m个元素,求删除元素之前序列有多少个逆序对。
【思路】
cdq分治
这个题转化一下可以变成刚刚做过的三维偏序。
首先有两个量:序 和 值,可以将样例写成
x 1
2 3 4 5
y 1 5 3 4 2
然后因为我们要删除一些东西,所以加上时间,则样例变为
t 1 2 3 4 5
x 3 5 4 1 2
y 3 2 4 1 5
删除顺序就是按照t从大到小。我们把它看作t从小到大的插入结点。
则我们要求的是,一个结点在t时刻插入,左边有多少个比它大,右边有多少个比它小,设这个点为(t0,x0,y0),则我们要求的就是满足
t<t0,x<x0,y>y0
t<t0,x>x0,y<y0
的点数。因为具体的值对结果并无影响我们可以通过把a改成n-a+1来改变符号的方向,具体就是求满足
t<t0,x<x0,y<(n-y0+1)
t<t0,x<(n-x0+1),y<y0
的点数。
于是问题变成了刚做过的 陌上花开 问题。
最后统计每个时间点发生之前产生的所有逆序对。
【代码】
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define rep(a,b,c) for(int a=b;a<=c;++a) 5 using namespace std; 6 7 typedef long long ll; 8 const int N =3*1e5+10; 9 10 void read(int &x) { 11 char c=getchar(); x=0; 12 while(!isdigit(c)) c=getchar(); 13 while(isdigit(c)) x=x*10+c-'0',c=getchar(); 14 } 15 16 struct Node { 17 int a,b,c,ans; 18 bool operator<(const Node& rhs) const { 19 return a<rhs.a; 20 } 21 }q[N],T[N]; 22 bool cmp(const Node& x,const Node& y) 23 { 24 return x.b<y.b||(x.b==y.b&&x.c>y.c); 25 } 26 27 int n,m,mx,C[N],rk[N]; 28 ll ans[N]; 29 30 void add(int x,int v) 31 { 32 for(;x<=mx;x+=x&-x) C[x]+=v; 33 } 34 int query(int x) 35 { 36 int res=0; 37 for(;x;x-=x&-x) res+=C[x]; 38 return res; 39 } 40 41 void solve(int l,int r) 42 { 43 if(l==r) return ; 44 int mid=(l+r)>>1; 45 solve(l,mid) , solve(mid+1,r); 46 int l1=l,l2=mid+1,i; 47 while(l2<=r) { 48 while(l1<=mid&&q[l1].b<q[l2].b) { 49 add(q[l1].c,1); 50 l1++; 51 } 52 q[l2].ans+=query(q[l2].c); 53 l2++; 54 } 55 for(i=l;i<l1;i++) add(q[i].c,-1); 56 l1=l,l2=mid+1; int now=l; 57 while(l1<=mid||l2<=r) { 58 if(l2>r||l1<=mid&&cmp(q[l1],q[l2])) T[now++]=q[l1++]; 59 else T[now++]=q[l2++]; 60 } 61 for(int i=l;i<=r;i++) q[i]=T[i]; 62 } 63 64 int main() 65 { 66 read(n),read(m); mx=n+5; 67 rep(i,1,n) { q[i].b=i; read(q[i].c); } 68 int a; 69 rep(i,1,m) { read(a); rk[a]=i; } 70 int sz=m; 71 rep(i,1,n) if(!rk[i]) rk[i]=++sz; 72 rep(i,1,n) q[i].a=n-rk[q[i].c]+1; 73 sort(q+1,q+n+1); 74 rep(i,1,n) q[i].b=n-q[i].b+1; 75 solve(1,n); 76 sort(q+1,q+n+1); 77 rep(i,1,n) { 78 q[i].b=n-q[i].b+1; 79 q[i].c=n-q[i].c+1; 80 } 81 solve(1,n); 82 rep(i,1,n) ans[q[i].a]=q[i].ans; 83 rep(i,1,n) ans[i]+=ans[i-1]; 84 for(int i=n;i>n-m;i--) 85 printf("%lld ",ans[i]); 86 return 0; 87 }