【bzoj3295】【Cqoi2011】【动态逆序对】【树状数组套平衡树】

来源:互联网 发布:大数据赚钱 编辑:程序博客网 时间:2024/05/17 04:58

Description

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

Input

输入第一行包含两个整数nm,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
 

Output

 
输出包含m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4
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)。

HINT

N<=100000 M<=50000

题解:

          可以求出一开始的逆序对个数

          删除一个数相当于减少了这个数之前比这个数大的数和这个数之后比这个数小的数.

          这个可以用树套树来处理.

          线段树套平衡树应该是会T,改成树状数组套平衡树就可以了.

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#define N 100010using namespace std;int a[N],root[N<<2],ls[N*30],rs[N*30],t[N],p[N],sz,n,m,tmp,x,tt;long long ans;struct treap{int s,w,rd,v;}tr[N*30];int read(){  int x(0);  char ch=getchar();  while (ch<'0'||ch>'9') ch=getchar();  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();  return x;}void add(int x){for (int i=x;i<=n;i+=i&(-i)) t[i]++;}int que(int x){  int ans(0);  for (int i=x;i;i-=i&(-i)) ans+=t[i];  return ans;}void update(int k){  tr[k].s=tr[ls[k]].s+tr[rs[k]].s+tr[k].w;}void lturn(int &k){  int t=rs[k];rs[k]=ls[rs[k]];ls[t]=k;  update(k);update(t);k=t;} void rturn(int &k){  int t=ls[k];ls[k]=rs[ls[k]];rs[t]=k;  update(k);update(t);k=t;}void insert(int &k,int v){  if (!k){k=++sz;tr[k].s=tr[k].w=1;tr[k].v=v;tr[k].rd=rand();return;}  if (tr[k].v==v) tr[k].w++;  else if (v<tr[k].v){insert(ls[k],v);if (tr[ls[k]].rd<tr[k].rd) rturn(k);}  else{insert(rs[k],v);if (tr[rs[k]].rd<tr[k].rd) lturn(k);}  update(k); }void del(int &k,int v){  if (!k) return;  if (tr[k].v==v){    if (tr[k].w>1) tr[k].w--;    else{      if (ls[k]*rs[k]==0) k=ls[k]+rs[k];  else if (tr[ls[k]].rd<tr[k].rd){rturn(k);del(k,v);}      else {lturn(k);del(k,v);}    }  }  else if (v<tr[k].v) del(ls[k],v);  else del(rs[k],v);  update(k);}void build(int x,int v){for (int i=x;i<=n;i+=i&(-i)) insert(root[i],v);}void after(int k,int v){  if (!k) return;  if (tr[k].v==v) tmp+=tr[rs[k]].s;  else if (v<tr[k].v){tmp+=tr[k].w+tr[rs[k]].s;after(ls[k],v);}  else after(rs[k],v);}void pre(int k,int v){  if (!k) return;  if (tr[k].v==v) tmp+=tr[ls[k]].s;  else if (v<tr[k].v) pre(ls[k],v);  else{tmp+=tr[k].w+tr[ls[k]].s;pre(rs[k],v);}}void getafter(int x,int v){  for (int i=x;i;i-=i&(-i)) after(root[i],v);}void getpre(int x,int v){  for (int i=x;i;i-=i&(-i)) pre(root[i],v);}void change(int x,int v){for (int i=x;i<=n;i+=i&(-i)) del(root[i],v);}int main(){  n=read();m=read();  for (int i=1;i<=n;i++) a[i]=read(),p[a[i]]=i;  for (int i=1;i<=n;i++) build(i,a[i]);  for (int i=n;i>=1;i--){ans+=que(a[i]);add(a[i]);}  for (int i=1;i<=m;i++){    x=read();    printf("%lld\n",ans);    tmp=0;getafter(p[x],x);ans-=tmp;    tmp=0;getpre(n,x);tt=tmp;    tmp=0;getpre(p[x],x);ans-=tt-tmp;change(p[x],x);  } }


0 0