zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    VSCode:无法创建临时目录
    网页很卡的原因
    用css做三角形
    移动端加载页面出现抖动、未加载完成时布局杂乱问题解决
    vue中使用axios进行ajax请求数据(跨域配置)
    fetch和XMLHttpRequest
    1-5-JS基础-数组应用及实例应用
    图片左右切换
    轮播图片切换
    轮播图片切换(函数合并)
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8176224.html
Copyright © 2011-2022 走看看