1. 程式人生 > >[Luogu P3157][CQOI2011]動態逆序對 (樹套樹)

[Luogu P3157][CQOI2011]動態逆序對 (樹套樹)

題面

傳送門:[CQOI2011]動態逆序對


Solution

一開始我看到pty巨神寫這套題的時候,第一眼還以為是個SB題:這不直接開倒車線段樹統計就完成了嗎?

然後冷靜思考了一分鐘,猛然發現單純的線段樹並不能解決這個問題,好像還要在外面再套上一顆樹。

這就很shit了。你問我資磁不資磁樹套樹,我是不資磁的,樹套樹是暴力資料結構,我能資磁嗎?

很不幸,昨天現實狠狠地打了我一臉:時間不夠開新坑的,不切題又渾身難受,找了半天題,還是把這道題拉了出來(哈,真香)

 

不扯淡了,這題還是很顯然的。

考慮開倒車,我們一個一個往裡面加樹,然後統計一下這個數能對當前的數列有多少貢獻,貢獻很容易想到:我們只需要找到在他後面比他小的數以及在他前面比他大的數就好。

然後本蒟蒻寫了個蜜汁線段樹套splay。

時間複雜度是$O(n*log^2n)$,空間複雜度為$O(n*logn)$。理論上應該能過

可惜現實非常苦感:

 

 

.....

那咋搞啊。

那我上個線段樹套權值線段樹吧

然後又碼了半個小時。

時空複雜度均為$O(n*log^2n)$ (這明顯要MLE啊,問題是題解蜜汁能過)

可惜現實依舊苦感:

 

難道,改資料了?

接著,我copy了一發題解,交上去,A掉了.......

到目前為止,我還是想不通為啥開同樣的陣列,他A了,我T了。難道說他外層套的樹狀陣列可以有效減少空間的消耗?

想不通,還請個位dalao賜教。


Code (並不能A)

線段樹套splay:

#include<iostream>
#include<cstdio>
using namespace std;
long long read()
{
    long long x=0,f=1; char c=getchar();
    while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int N=100000+1000;
struct
TreeInTree { #define mid ((now_l+now_r)>>1) #define lson (now<<1) #define rson (now<<1|1) #define root son[r][1] static const int M=N*25; int fa[M],son[M][2],size[M],cnt[M],num[M],to; inline void update(int x) { size[x]=size[son[x][0]]+size[son[x][1]]+cnt[x]; } inline void rotate(int x,int type) { int y=fa[x],z=fa[y]; son[z][y==son[z][1]]=x,fa[x]=z; son[y][!type]=son[x][type],fa[son[x][type]]=y; son[x][type]=y,fa[y]=x; update(y),update(x); } void splay(int x,int to) { while(fa[x]!=to) { if(x==son[fa[x]][fa[x]==son[fa[fa[x]]][1]] and fa[fa[x]]!=to) rotate(fa[x],x==son[fa[x]][0]); rotate(x,x==son[fa[x]][0]); } } void Insert(int w,int r) { if(root==0) { root=++to,fa[root]=r; num[root]=w,update(root); return; } int now=root,last=root; while(now!=0) last=now,now=son[now][w>num[now]]; now=++to,fa[now]=last,son[last][w>num[last]]=now; num[now]=w,update(now); splay(now,r); } int Query1(int x,int r) { int now=root,ans=0; while(now!=0) { if(num[now]>=x) now=son[now][0]; else { if(num[now]>num[ans]) ans=now; now=son[now][1]; } } if(ans==0) return 0; splay(ans,r); return size[son[ans][0]]+cnt[ans]; } int Query2(int x,int r) { int now=root,ans=0; num[0]=0x3f3f3f3f; while(now!=0) { if(num[now]>x) { if(num[now]<num[ans]) ans=now; now=son[now][0]; } else now=son[now][1]; } num[0]=0; if(ans==0) return 0; splay(ans,r); return size[son[ans][1]]+cnt[ans]; } int t[N<<2]; void Build(int now,int now_l,int now_r) { t[now]=++to; if(now_l==now_r) return; Build(lson,now_l,mid); Build(rson,mid+1,now_r); } inline void Insert2(int x,int w,int now,int now_l,int now_r) { Insert(w,t[now]); if(now_l!=now_r) { if(x<=mid) Insert2(x,w,lson,now_l,mid); else Insert2(x,w,rson,mid+1,now_r); } } int Query3(int l,int r,int w,int type,int now,int now_l,int now_r) { if(now_l>=l and now_r<=r) { if(type==1) return Query1(w,t[now]); else return Query2(w,t[now]); } int sum=0; if(l<=mid) sum+=Query3(l,r,w,type,lson,now_l,mid); if(r>mid) sum+=Query3(l,r,w,type,rson,mid+1,now_r); return sum; } #undef mid #undef lson #undef rson }tit; int n,m,p[N],q[N],unOK[N]; long long ans[N]; int main() { freopen("3157.in","r",stdin); freopen("3157.out","w",stdout); int t=clock(); n=read(),m=read(); for(int i=1;i<=n;i++) p[read()]=i; for(int i=1;i<=m;i++) q[i]=read(),unOK[q[i]]=true; tit.Build(1,1,n); for(int i=1;i<=n;i++) if(unOK[i]==false) { tit.Insert2(p[i],i,1,1,n); ans[m+1]+=tit.Query3(p[i],n,i,1,1,1,n)+tit.Query3(1,p[i],i,2,1,1,n); } for(int i=m;i>=1;i--) { tit.Insert2(p[q[i]],q[i],1,1,n); ans[i]=ans[i+1]+tit.Query3(p[q[i]],n,q[i],1,1,1,n)+tit.Query3(1,p[q[i]],q[i],2,1,1,n); } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); cerr<<clock()-t<<endl; return 0; }

 

線段樹套權值線段樹

#include<iostream>
#include<cstdio>
using namespace std;
long long read()
{
    long long x=0,f=1; char c=getchar();
    while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int N=100000+1000;
int n,m,p[N],q[N],unOK[N];
long long ans[N];
struct TreeInTree
{
    #define mid ((now_l+now_r)>>1)
    #define lson (now<<1)
    #define rson (now<<1|1)
    static const int M=N*200;
    int son[M][2],num[M],to;
    inline void update(int x) 
    {
        num[x]=num[son[x][0]]+num[son[x][1]];
    }
    void Insert(int x,int now,int now_l,int now_r)
    {
        if(now_l==now_r)
        {
            num[now]++;
            return;
        }
        if(now>to) 
            cerr<<to;
        if(x<=mid)
        {
            if(son[now][0]==0) son[now][0]=++to;
            Insert(x,son[now][0],now_l,mid);
        }
        else
        {
            if(son[now][1]==0) son[now][1]=++to;
            Insert(x,son[now][1],mid+1,now_r);
        }
        update(now);
    }
    int Query1(int l,int r,int now,int now_l,int now_r)
    {
        if(l>r) return 0;
        if((now_l>=l and now_r<=r) or now==0)
            return num[now];
        int t_ans=0;
        if(l<=mid) t_ans+=Query1(l,r,son[now][0],now_l,mid);
        if(r>mid) t_ans+=Query1(l,r,son[now][1],mid+1,now_r);
        return t_ans;
    }
    int t[N<<2];
    void Build(int now,int now_l,int now_r)
    {
        t[now]=++to;
        if(now_l==now_r) return;
        Build(lson,now_l,mid);
        Build(rson,mid+1,now_r);
    }
    inline void Insert2(int x,int w,int now,int now_l,int now_r)
    {
        Insert(w,t[now],1,n);
        if(now_l!=now_r)
        {
            if(x<=mid)    Insert2(x,w,lson,now_l,mid);
            else Insert2(x,w,rson,mid+1,now_r);
        }
    }
    int Query3(int l,int r,int w,int type,int now,int now_l,int now_r)
    {
        if(now_l>=l and now_r<=r)
        {
            if(type==1) return Query1(1,w-1,t[now],1,n);
            else return Query1(w+1,n,t[now],1,n);
        }
        int sum=0;
        if(l<=mid) sum+=Query3(l,r,w,type,lson,now_l,mid);
        if(r>mid) sum+=Query3(l,r,w,type,rson,mid+1,now_r);
        return sum;
    }
    #undef mid
    #undef lson
    #undef rson
}tit;
int main()
{    
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        p[read()]=i;
    for(int i=1;i<=m;i++)
        q[i]=read(),unOK[q[i]]=true;
    
    tit.Build(1,1,n);
    for(int i=1;i<=n;i++)
        if(unOK[i]==false)
        {
            tit.Insert2(p[i],i,1,1,n);
            ans[m+1]+=tit.Query3(p[i],n,i,1,1,1,n)+tit.Query3(1,p[i],i,2,1,1,n);
        }
    for(int i=m;i>=1;i--)
    {
        tit.Insert2(p[q[i]],q[i],1,1,n);
        ans[i]=ans[i+1]+tit.Query3(p[q[i]],n,q[i],1,1,1,n)+tit.Query3(1,p[q[i]],q[i],2,1,1,n);
    }
    
    for(int i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    return 0;
}