http://www.lydsy.com/JudgeOnline/problem.php?id=3295
Description
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
——————————————————————————————
这题不开longlong成功见祖宗……
乍一看我们想不到CDQ,但是显然删除操作不好整,我们将删除变成插入,插入的时间点为t,插入的位置为p,插入的值为n。
则三元组(t,p,n)它的逆序对需要满足t0<t,p0<p,n0>n或者t0<t,p0>p,n0<n。
这不就成三维偏序了吗?解完之后求一遍前缀和即是答案。
#include<cstdio> #include<queue> #include<cctype> #include<cstring> #include<vector> #include<algorithm> using namespace std; typedef long long ll; const int N=100001; inline int read(){ int X=0,w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct del{ int t; int p; int n; }q[N],tmp[N]; ll m,n,ans[N],pos[N],tree[N]; inline int lowbit(int t){return t&(-t);} void add(int x,int y){//将a[x]+y for(int i=x;i<=n;i+=lowbit(i))tree[i]+=y; return; } ll query(int x){//1-x区间和 ll res=0; for(int i=x;i>0;i-=lowbit(i))res+=tree[i]; return res; } void cdq(int l,int r){ if(l>=r)return; int mid=(l+r)>>1; cdq(l,mid);cdq(mid+1,r); for(int i=l,j=l,p=mid+1;i<=r;i++){ if(j<=mid&&(p>r||q[j].n>q[p].n))tmp[i]=q[j++]; else tmp[i]=q[p++]; } for(int i=l;i<=r;i++){ q[i]=tmp[i]; if(q[i].t<=mid)add(q[i].p,1); else ans[q[i].t]+=query(q[i].p); } for(int i=l;i<=r;i++)if(q[i].t<=mid)add(q[i].p,-1); for(int i=r;i>=l;i--){ if(q[i].t<=mid)add(q[i].p,1); else ans[q[i].t]+=query(n)-query(q[i].p); } for(int i=l;i<=r;i++)if(q[i].t<=mid)add(q[i].p,-1); return; } bool vis[N]; int main(){ n=read(); m=read(); for(int i=1;i<=n;i++)pos[read()]=i; for(int i=n;i>=n-m+1;i--){ q[i].t=i; q[i].n=read(); q[i].p=pos[q[i].n]; vis[q[i].n]=1; } int cnt=n-m; for(int i=1;i<=n;i++){ if(!vis[i]){ q[cnt].t=cnt; q[cnt].n=i; q[cnt--].p=pos[i]; } } cdq(1,n); for(int i=1;i<=n;i++)ans[i]+=ans[i-1]; for(int i=n;i>=n-m+1;i--)printf("%lld ",ans[i]); return 0; }