【Luogu】P1393动态逆序对(树套树)

  题目链接

  树套树。

  每次删掉x的时候会减去1到x-1里比x位置的数大的数和它构成的逆序对,以及x+1到n里比x位置的数小的数和它构成的逆序对。

  顺带一提我发现平衡树insert的时候不是要splay一下嘛

  如果改成每插入50个splay一下会快的飞起

  我这道题就是这么卡过去的23333

  放上代码 

  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<algorithm>
#define mid ((l+r)>>1)
#define left (rt<<1)
#define right (rt<<1|1)
#define lson l,mid,left
#define rson mid+1,r,right
using namespace std;
int CNT;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int root[1000000];
int q[100010];

struct Splay{
    struct Node{
        int size,sum,e[2],val,fa;
    }tree[1000000];
    int point,tot;
    Splay(){    point=tot=0;    }
    inline int iden(int x){    return x==tree[tree[x].fa].e[1];    }
    inline void connect(int x,int fa,int how){    tree[x].fa=fa;    tree[fa].e[how]=x;    }
    inline void update(int x){
        tree[x].size=tree[x].sum;
        if(tree[x].e[0])    tree[x].size+=tree[tree[x].e[0]].size;
        if(tree[x].e[1])    tree[x].size+=tree[tree[x].e[1]].size;
    }
    void rotate(int x,int rt){
        int y=tree[x].fa;    int r=tree[y].fa;
        if(root[rt]==y)    root[rt]=x;
        int sony=iden(x),sonr=iden(y);
        int b=tree[x].e[sony^1];
        connect(b,y,sony);
        connect(y,x,sony^1);
        connect(x,r,sonr);
        update(y);update(x);
    }
    void splay(int pos,int to,int rt){
        to=tree[to].fa;
        while(tree[pos].fa!=to){
            if(tree[tree[pos].fa].fa==to)    rotate(pos,rt);
            else
                if(iden(pos)==iden(tree[pos].fa)){    rotate(tree[pos].fa,rt);    rotate(pos,rt);    }
                else{    rotate(pos,rt);    rotate(pos,rt);    }
        }
    }
    int create(int val,int fa){
        tree[++tot].val=val;    tree[tot].sum=tree[tot].size=1;    tree[tot].fa=fa;
        return tot;
    }
    int find(int val,int rt){
        int now=root[rt];
        while(1){
            if(!now)    return 0;
            if(tree[now].val==val){
                splay(now,root[rt],rt);
                return now;
            }
            int nxt=val>tree[now].val?1:0;
            if(!tree[now].e[nxt])    return 0;
            now=tree[now].e[nxt];
        }
    }
    int build(int val,int rt){
        point++;
        if(!root[rt]){
            root[rt]=create(val,0);
            return root[rt];
        }
        int now=root[rt];
        while(1){
            tree[now].size++;
            if(tree[now].val==val){
                tree[now].sum++;
                return now;
            }
            int nxt=val>tree[now].val?1:0;
            if(!tree[now].e[nxt]){
                int p=create(val,now);
                connect(p,now,nxt);
                return p;
            }
            now=tree[now].e[nxt];
        }
    }
    void insert(int val,int rt){
        int p=build(val,rt);
        if((++CNT)%50==0){
            splay(p,root[rt],rt);
            CNT=0;
        }
    }
    void dele(int x){
        tree[x].e[0]=tree[x].e[1]=0;
        if(x==tot)    tot--;
    }
    void pop(int val,int rt){
        int deal=find(val,rt);
        if(!deal)    return;
        point--;
        if(tree[deal].sum>1){    tree[deal].sum--;    tree[deal].size--; return;}
        if(!tree[deal].e[0]){
            root[rt]=tree[deal].e[1];
            tree[root[rt]].fa=0;
        }
        else{
            int le=tree[deal].e[0];
            while(tree[le].e[1])    le=tree[le].e[1];
            splay(le,tree[deal].e[0],rt);
            int ri=tree[deal].e[1];
            connect(ri,le,1);    tree[le].fa=0;
            root[rt]=le;
            update(le);
        }
        dele(deal);
    }
    int rank(int val,int rt){
        int ans=0,now=root[rt];
        while(1){
            if(!now)    return ans;
            if(tree[now].val==val){
                ans+=tree[tree[now].e[0]].size;
                return ans;
            }
            if(val<tree[now].val)    now=tree[now].e[0];
            else{
                ans+=tree[tree[now].e[0]].size+tree[now].sum;
                now=tree[now].e[1];
            }
        }
    }
    int arank(int val,int rt){
        int ans=0,now=root[rt];
        while(1){
            if(!now)    return ans;
            if(tree[now].val==val){
                ans+=tree[tree[now].e[1]].size;
                return ans;
            }
            if(val<tree[now].val){
                ans+=tree[tree[now].e[1]].size+tree[now].sum;
                now=tree[now].e[0];
            }
            else    now=tree[now].e[1];
        }
    }
    int ask(int val,int rt,int opt){
        if(opt==1)    return arank(val,rt);
        else        return rank(val,rt);
    }
}s;

void build(int l,int r,int rt){
    for(int i=l;i<=r;++i)    s.insert(q[i],rt);
    if(l==r)    return;
    build(lson);
    build(rson);
}

int query(int from,int to,int val,int l,int r,int rt,int opt){
    if(from>to)    return 0;
    if(from<=l&&to>=r)    return s.ask(val,rt,opt);
    int cnt=0;
    if(from<=mid)    cnt+=query(from,to,val,lson,opt);
    if(to>mid)        cnt+=query(from,to,val,rson,opt);
    return cnt;
}

void Delete(int o,int val,int l,int r,int rt){
    s.pop(val,rt);
    if(l==r)    return;
    if(o<=mid)    Delete(o,val,lson);
    else        Delete(o,val,rson);
}

int ans;

int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;++i)    q[i]=read();
    build(1,n,1);
    for(int i=1;i<=n;++i)    ans+=query(1,i-1,q[i],1,n,1,1);
    printf("%d",ans);
    for(int i=1;i<=m;++i){
        int pos=read();
        ans-=query(1,pos-1,q[pos],1,n,1,1);
        ans-=query(pos+1,n,q[pos],1,n,1,0);
        printf(" %d",ans);
        Delete(pos,q[pos],1,n,1);
    }
    return 0;
}

 

posted @ 2018-01-02 11:08  Konoset  阅读(206)  评论(0编辑  收藏  举报