BZOJ3295: [Cqoi2011]动态逆序对
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
随便写好了。。。
写个树状数组套平衡树,光荣踩时过
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=100010; const int maxnode=4000010; struct Node { Node* ch[2]; int r,s,v,del; void maintain() {s=ch[0]->s+ch[1]->s+(!del);} }nodes[maxnode],*null=&nodes[0]; int ToT; Node* newnode(int v) { Node* o=&nodes[++ToT];o->ch[0]=o->ch[1]=null; o->del=0;o->s=1;o->v=v;return o; } void rotate(Node* &o,int d) { Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o; o->maintain();k->maintain();o=k; } void insert(Node* &o,int v) { if(o==null) o=newnode(v); else { int d=v>o->v;insert(o->ch[d],v); if(o->ch[d]->r>o->r) rotate(o,d^1); else o->maintain(); } } int query(Node* &o,int v) { if(o==null) return 0; if(v<=o->v) return query(o->ch[0],v); return query(o->ch[1],v)+o->ch[0]->s+(!o->del); } void remove(Node* &o,int v) { if(v==o->v) o->del=1; else remove(o->ch[v>o->v],v); o->maintain(); } void print(Node* &o) { if(o==null) return; print(o->ch[0]); if(!o->del) printf("%d ",o->v); print(o->ch[1]); } int n,m,A[maxn],pos[maxn],c[maxn]; struct Tree { Node* root[maxn]; void add(int x,int v) { for(;x<=n;x+=x&-x) insert(root[x],v); } int sum(int x,int v) { int res=0; for(;x;x-=x&-x) res+=query(root[x],v); return res; } void del(int x,int v) { for(;x<=n;x+=x&-x) remove(root[x],v); } }T1,T2; void add(int x) { for(;x<=n;x+=x&-x) c[x]++; } int query(int x) { int sum=0; for(;x;x-=x&-x) sum+=c[x]; return sum; } long long ans; int main() { n=read();m=read(); rep(i,1,n) { add(n-(A[i]=read())+1);ans+=query(n-A[i]); T1.root[i]=T2.root[i]=null;pos[A[i]]=i; } rep(i,1,n) T1.add(i,n-A[i]+1),T2.add(n-i+1,A[i]); printf("%lld\n",ans); while(--m) { int x=pos[read()]; ans-=T1.sum(x-1,n-A[x]+1)+T2.sum(n-x,A[x]); T1.del(x,n-A[x]+1);T2.del(n-x+1,A[x]); printf("%lld\n",ans); } return 0; }