UVA 11990 bit + cdq 分治

題意:動態逆序對

做法:對於刪除操作可以當做逆向的添加操作 , 所以對於每個數字都有三個屬性 (T,ID,Num)  所以這道題其實就是一個三維偏序問題 。 對於一個數 只需要 左邊比它大的數 和右邊比它小的數 ,我們可以用一個bit logn 進行操作。

三位偏序 可以用CDQ 減去一維 , 我們先把左邊算出來 ,再把右邊算出來,最後處理中間部分的。

對於中間的部分 用雙指針 一個指向 L,MID(時間)。 一個指向MID+1,R(時間) 就可以消除T的影響 ,  同時左右兩邊滿足 id 是遞增的!


#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct node
{
    int t,num,id;
}a[maxn],b[maxn];
int n, m;
int pos[maxn];
ll ans[maxn];
int l[maxn],r[maxn],bit[maxn];

inline void updata(int pos,int val)
{
    for(int i=pos;i<=n;i+=(i&(-i)) ) bit[i]+=val;
}
inline int query(int pos)
{
    int ans=0;
    for(int i=pos;i;i-=(i&(-i))) ans+=bit[i];
    return ans;
}

inline void cdq(int begin,int end)
{
   if(begin >= end) return;
   int mid=(begin+end)>>1;
   int l1 = begin ,l2=mid+1,temp;

    for(int i=begin;i<=end;++i)
    {
        if(a[i].t<=mid) b[l1++]=a[i];
        else b[l2++]=a[i];
    }
    for(int i=begin;i<=end;++i) a[i]=b[i];
    temp=begin;
    for(int i=mid+1;i<=end;++i)
    {
        for( ; temp<=mid &&a[temp].id<a[i].id;temp++) updata(a[temp].num,1);
        l[a[i].t]+=(temp - begin - query(a[i].num));
    }
    for(int i=begin;i<=temp-1;i++) updata(a[i].num,-1);

    temp = mid;
    for(int i=end;i>=mid+1;--i)
    {
        for(; temp>=begin && a[temp].id >a[i].id ; temp--) updata(a[temp].num,1);
        r[a[i].t] += query(a[i].num-1);
    }
    for(int i=temp+1;i<=mid;i++) updata(a[i].num , -1);
    cdq(begin,mid); cdq(mid+1,end);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        memset(bit,0,sizeof(bit));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i].num);
            a[i].id=i;  a[i].t=0;
            pos[a[i].num]=i;
        }
        int tt=n,x;
        for(int i=1;i<=m;++i)
        {
            scanf("%d",&x);
            a[pos[x]].t = tt--;
        }
        for(int i=1;i<=n;++i)
        {
            if(a[i].t==0) a[i].t=tt--;
        }
        cdq(1,n);
        for(int i=1;i<=n;++i) ans[i]=ans[i-1] + l[i] + r[i];
        for(int i=n;i>=n-m+1;--i) printf("%lld\n",ans[i]);
    }
    return 0;
}


























































 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章