• 【BZOJ4825】单旋(AHOI&HNOI2017)-set+树状数组


    测试地址:单旋
    做法:本题需要用到set+树状数组。
    首先,我们注意到题目中单旋只涉及到最小值和最大值,考虑到旋转是对称的,我们先只考虑单旋最小值的情况。
    显然目标点每次都是往右旋转,往右旋转对点的影响是:该点的右子树深度没有影响,该点深度减少1,而对于其它影响到的点深度都增加1。那么我们可以得到一个非常优美的性质:每一次单旋,除了以目标点为根的子树外,其它所有点深度都增加1。并且我们还能知道,进行一次这样的操作后树的形态也不会发生很大的改变,具体来说就是,目标点的右子树变成目标点父亲的左子树,目标点接到根的上面,这就说明树的形态是可以维护的。
    接下来我们一一讨论涉及到的操作。首先是插入操作,你要找到这个点在DFS序上的前驱和后继,那么这个点的深度就是这两点深度的最大值+1(可以画个图理解一下),我们可以用set来维护DFS序。然后对于单旋操作,先把所有的点深度+1,因为我们知道它的子树不受影响,那么我们找到该子树对应的区间,把深度减掉1,而对于目标点,则是把深度直接修改为1。待删除的情况类似,我就不赘述了。这里主要讨论如何找到子树对应的区间,观察发现这棵子树对应的区间为DFS序上目标点和它的父亲之间的这些点。那么我们用set维护DFS序,因为涉及到的修改操作有区间修改和单点询问,可以差分一下用树状数组维护,同时也要维护树的具体结构。那么我们就做完了这一题,时间复杂度为O(nlogn)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,op[100010],a[100010],cnt=0,sum[100010];
    int fa[100010],ch[100010][2];
    struct forsort
    {
        int id,val;
    }f[100010];
    set<int> S;
    set<int>::iterator it;
    
    bool cmp(forsort a,forsort b)
    {
        return a.val<b.val;
    }
    
    void init()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&op[i]);
            if (op[i]==1)
            {
                scanf("%d",&f[++cnt].val);
                f[cnt].id=i;
            }
        }
    
        sort(f+1,f+cnt+1,cmp);
        for(int i=1;i<=cnt;i++)
            a[f[i].id]=i;
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int x,int d)
    {
        for(int i=x;i<=n+1;i+=lowbit(i))
            sum[i]+=d;
    }
    
    int query(int x)
    {
        int ans=0;
        for(int i=x;i;i-=lowbit(i))
            ans+=sum[i];
        return ans;
    }
    
    void Add(int s,int t,int d)
    {
        if (s>t) return;
        add(s,d);
        add(t+1,-d);
    }
    
    void modify(int x,int d)
    {
        int now=query(x);
        Add(x,x,d-now);
    }
    
    void work()
    {
        int nowrt=0;
        for(int i=1;i<=n;i++)
        {
            if (op[i]==1)
            {
                it=S.lower_bound(a[i]);
                int ldep,rdep,lpos,rpos;
                if (it!=S.end()) rdep=query(rpos=*it);
                else rdep=rpos=0;
                if (it!=S.begin())
                {
                    it--;
                    ldep=query(lpos=*it);
                }
                else ldep=lpos=0;
                ch[a[i]][0]=ch[a[i]][1]=0;
                if (ldep>rdep)
                {
                    fa[a[i]]=lpos;
                    if (lpos) ch[lpos][1]=a[i];
                }
                else
                {
                    fa[a[i]]=rpos;
                    if (rpos) ch[rpos][0]=a[i];
                }
                S.insert(a[i]);
                modify(a[i],max(ldep,rdep)+1);
                printf("%d
    ",max(ldep,rdep)+1);
                if (!nowrt) nowrt=a[i];
            }
            if (op[i]==2||op[i]==4)
            {
                it=S.begin();
                int v=*it;
                printf("%d
    ",query(v));
                if (fa[v]) Add(v+1,fa[v]-1,-1);
                else Add(v+1,n,-1);
                if (fa[v]) ch[fa[v]][0]=ch[v][1];
                if (ch[v][1])
                {
                    fa[ch[v][1]]=fa[v];
                    if (!fa[v]) nowrt=ch[v][1];
                }
                if (op[i]==2)
                {
                    Add(1,n,1);
                    fa[v]=0;
                    if (nowrt!=v)
                    {
                        ch[v][1]=nowrt;
                        fa[nowrt]=v;
                    }
                    nowrt=v;
                    modify(v,1);
                }
                else
                {
                    S.erase(v);
                    if (nowrt==v) nowrt=ch[v][1];
                }
            }
            if (op[i]==3||op[i]==5)
            {
                it=S.end();
                it--;
                int v=*it;
                printf("%d
    ",query(v));
                if (fa[v]) Add(fa[v]+1,v-1,-1);
                else Add(1,v-1,-1);
                if (fa[v]) ch[fa[v]][1]=ch[v][0];
                if (ch[v][0])
                {
                    fa[ch[v][0]]=fa[v];
                    if (!fa[v]) nowrt=ch[v][0];
                }
                if (op[i]==3)
                {
                    Add(1,n,1);
                    fa[v]=0;
                    if (nowrt!=v)
                    {
                        ch[v][0]=nowrt;
                        fa[nowrt]=v;
                    }
                    nowrt=v;
                    modify(v,1);
                }
                else
                {
                    S.erase(v);
                    if (nowrt==v) nowrt=ch[v][0];
                }
            }
        }
    }
    
    int main()
    {
        init();
        work();
    
        return 0;
    }
  • 相关阅读:
    python字符串以单词形式反转
    python if 语句的练习
    Python对元祖的操作
    Python对列表的操作
    Python对字符串的操作
    导出EXCEL【Web方式HTML通过拼接html中table】
    链接点击跳动问题
    maven报uri is not registered错误
    maven配置
    三级分类的sql语句
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793389.html
Copyright © 2020-2023  润新知