P1393 动态逆序对(主席树+树状数组)

题目描述

对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i<j的有序对(i,j)的个数。你需要计算出一个序列的逆序对组数及其删去其中的某个数的逆序对组数。

输入输出格式

输入格式:

第一行,两个数n,m,表示序列中有n个数,要删去m个数

第二行n个数,表示给定的序列。

第三行m个数,第i个数di表示要删去原序列中的第di个数。

输出格式:

一行m+1个数。第一个数表示给定序列的逆序对组数,第i+1个数表示删去第di个数后序列的逆序对组数(删去的数不再恢复)

输入输出样例

输入样例#1: 复制
6 3
5 4 2 6 3 1
2 1 4
输出样例#1: 复制
11 7 4 2

说明

对于20%的数据,n≤2500

对于另30%的数据,m=0

对于100%的数据,n≤40000,m≤n/2,且保证第二行n个数互不相同,第三行m个数互不相同。




 

主席树+树状数组

因为数据保证每一数都互不相同。所以大数据就可以离散成小数据>之后套主席树

用H[]&Q[]表示在这个数之后(前)有多少比他小(大)的。(用树状数组求)

用主席数维护在这个数被删后多产生的贡献,多出的部分直接减掉。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define ll long long
#define lowbit(x) ((x)&(-x))
const int maxn=100000+9999;
using namespace std;
int n,m,num[maxn],H[maxn],Q[maxn],cnt,root[maxn*50],t[maxn],pos[maxn];
int xx[maxn],yy[maxn],totx,toty;

int A[100],B[100];
ll ans;
int LO(int x){return x&-x;}
int qsum(int x){
    int tmp=0;
    for(int i=x;i;i-=LO(i))
    tmp+=t[i];
    return tmp;
}
int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
    return an*f;
}
struct saber{
int r,l,sum;
}T[maxn*50];

int askless(int x,int y,int wi){
    int cnt1,cnt2,tmp=0;
    cnt1=cnt2=0;x--;
    for(int i=x;i;i-=LO(i))cnt1++,A[cnt1]=root[i];
    for(int i=y;i;i-=LO(i))cnt2++,B[cnt2]=root[i];
    int l=1,r=n;
    while(l!=r){
        int mid=(l+r)>>1;
        if(wi>mid){
            for(int i=1;i<=cnt1;i++)tmp-=T[ T[ A[i] ].l ].sum;
            for(int i=1;i<=cnt2;i++)tmp+=T[ T[ B[i] ].l ].sum;
            for(int i=1;i<=cnt1;i++)A[i]=T[ A[i] ].r;
            for(int i=1;i<=cnt2;i++)B[i]=T[ B[i] ].r;
            l=mid+1;
        }
        else {
            for(int i=1;i<=cnt1;i++)A[i]=T[ A[i] ].l;
            for(int i=1;i<=cnt2;i++)B[i]=T[ B[i] ].l;
            r=mid;
        }
    }
    return tmp;
}

int askmore(int p,int l,int r)
{
   int mid = l+r>>1; int t = 0; if (l==r) return 0;
   if (p<=mid)
   {
      for (int i=1;i<=totx;i++) t-=T[T[xx[i]].r].sum;
      for (int i=1;i<=toty;i++) t+=T[T[yy[i]].r].sum;
      for (int i=1;i<=totx;i++) xx[i]=T[xx[i]].l;
      for (int i=1;i<=toty;i++) yy[i]=T[yy[i]].l;
      return t+askmore(p,l,mid);
   }
   for (int i=1;i<=totx;i++)xx[i]=T[xx[i]].r;
   for (int i=1;i<=toty;i++)yy[i]=T[yy[i]].r;
   return askmore(p,mid+1,r);
}


void add(int &y,int l,int r,int wi){
    if(!y)cnt++,y=cnt;
    T[y].sum++;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(wi<=mid)add(T[y].l,l,mid,wi);
    else add(T[y].r,mid+1,r,wi);
}
struct da{
int wi,i;
}data[maxn];
bool cmp1(da x,da y){
    return x.wi<y.wi;
}
bool cmp2(da x,da y){
    return x.i<y.i;
}
void prepare(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        data[i].wi=read();
        data[i].i=i;
    }
    sort(data+1,data+1+n,cmp1);
    for(int i=1;i<=n;i++){
        data[i].wi=i;
    }
    sort(data+1,data+1+n,cmp2);
    for(int i=1;i<=n;i++)
    num[i]=data[i].wi;
}
int main(){
    prepare();
    for(int i=1;i<=n;i++){
        Q[i]=qsum(n)-qsum(num[i]);//Q在i这个点前面比it大的数贡献
        ans+=Q[i];
        for(int j=num[i];j<=n;j+=LO(j)){
            t[j]++;
        }
    }
    memset(t,0,sizeof(t));
    for(int i=n;i;i--){
        H[i]=qsum(num[i]-1);
        for(int j=num[i];j<=n;j+=LO(j))
        t[j]++;
    }
    printf("%lld ",ans);
    while(m){m--;

    int x=read();
       totx=toty=0;
      int c1=0;
      for (int i=0;i;i-=lowbit(i)) xx[++totx]=root[i];
      for (int i=x-1;i;i-=lowbit(i)) yy[++toty]=root[i];
      c1=askmore(num[x],1,n);



        ans-=(H[x]+Q[x]-c1-askless(x+1,n,num[x]) );
        for(int j=x;j<=n;j+=LO(j))add(root[j],1,n,num[x]);
    printf("%lld ",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhangbuang/p/10295054.html