刷题总结——动态逆序对(bzoj3295)
题目:
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
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
Source
题解:
同样的一道三维偏序题,将删除看成倒着插入,从而得出:<插入时间,位置,大小>(<t,a,b>),对于一个组数<t,a,b>,找寻(t>t1,a>a1且b<b1)的数量加到对应的ans[t]中,注意最后将ans叠加起来;
另外要注意在排完t后,a要正着排序求一遍ans然后倒着排序一遍ans,否则ans会少加(想想为什么单纯地求逆序对不用这样)
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=1e5+5; struct node { int t,a,b; }q[N],temp[N]; int n,m,tree[N],to[N],tag[N],tim; long long ans[N]; long long Ans; inline int R() { char c;int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } inline bool cmp(node a,node b) { return a.t<b.t; } inline bool comp(node a,node b) { return a.a<b.a; } inline void insert(int u,int v) { for(int i=u;i<=n;i+=(i&(-i))) if(tag[i]!=tim) tag[i]=tim,tree[i]=v; else tree[i]+=v; } inline bool comp2(node a,node b) { return a.a>b.a; } inline int query(int u) { int temp=0; for(int i=u;i;i-=(i&(-i))) if(tag[i]!=tim) continue; else temp+=tree[i]; return temp; } inline void solve1(int l,int r) { if(l==r) return; int mid=(l+r)/2; solve1(l,mid),solve1(mid+1,r); int i=l,j=mid+1,k=l;tim++; while(i<=mid&&j<=r) { if(comp(q[i],q[j])) { insert(q[i].b,1); temp[k++]=q[i++]; } else { ans[q[j].t]+=query(n)-query(q[j].b); temp[k++]=q[j++]; } } while(i<=mid) temp[k++]=q[i++]; while(j<=r) { ans[q[j].t]+=query(n)-query(q[j].b); temp[k++]=q[j++]; } for(j=l;j<=r;j++) q[j]=temp[j]; } inline void solve2(int l,int r) { if(l==r) return; int mid=(l+r)/2; solve2(l,mid),solve2(mid+1,r); int i=l,j=mid+1,k=l;tim++; while(i<=mid&&j<=r) { if(comp(q[j],q[i])) { insert(q[i].b,1); temp[k++]=q[i++]; } else { ans[q[j].t]+=query(q[j].b); temp[k++]=q[j++]; } } while(i<=mid) temp[k++]=q[i++]; while(j<=r) { ans[q[j].t]+=query(q[j].b); temp[k++]=q[j++]; } for(j=l;j<=r;j++) q[j]=temp[j]; } int main() { #ifndef ONLINE_JUDGE //freopen("a.in","r",stdin); #endif n=R(),m=R(); for(int i=1;i<=n;i++) { q[i].a=i,q[i].b=R(); to[q[i].b]=i; } int Time=n,a; for(int i=1;i<=m;i++) { a=R();q[to[a]].t=Time--; } for(int i=1;i<=n;i++) if(!q[i].t) q[i].t=Time--; sort(q+1,q+n+1,cmp); solve1(1,n); sort(q+1,q+n+1,cmp); solve2(1,n); for(int i=1;i<=n;i++) Ans+=ans[i]; for(int i=n;i>n-m;i--) printf("%lld\n",Ans),Ans-=ans[i]; return 0; }