【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\n",max(ldep,rdep)+1);
            if (!nowrt) nowrt=a[i];
        }
        if (op[i]==2||op[i]==4)
        {
            it=S.begin();
            int v=*it;
            printf("%d\n",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\n",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;
}
posted @ 2018-05-11 20:46  Maxwei_wzj  阅读(170)  评论(0编辑  收藏  举报