P3391 文艺平衡树

传送门
功能:实现区间反转
比如当前需要反转 [ l , r ] ,那么只需要把 l - 1 和 r + 1 分别旋到根节点,让后根节点右子树的左子树就是 [ l , r ] 区间内的数,在上面加一个 tag 懒标即可。
注意各个地方pushdown。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define pb push_back
#define mk make_pair
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

struct Splay
{
    struct node
    {
        int v,father;//v是结点值,father是父亲结点
        int ch[2];//ch[0] 左节点 ch[1] 右结点
        int sum;//包含自己下面有多少元素(非结点)
        int recy;//该结点元素出现次数(非结点)
        int tag;//区间标记
    };

    node e[N];
    int idx;
    int rot,a[N];

    void update(int x)//更新当前结点sum
    {
        e[x].sum=e[e[x].ch[0]].sum+e[e[x].ch[1]].sum+e[x].recy;
    }

    int identify(int x)//确定当前结点是父亲的左孩子还是右孩子
    {
        return e[e[x].father].ch[0]==x? 0:1;
    }

    void connect(int x,int f,int son)//x作为f的son(左右)儿子
    {
        e[x].father=f;
        e[f].ch[son]=x;
    }

    void pushdown(int x)//标记
    {
        if(x&&e[x].tag)
        {
            e[e[x].ch[0]].tag^=1;
            e[e[x].ch[1]].tag^=1;
            swap(e[x].ch[0],e[x].ch[1]);
            e[x].tag=0;
        }
    }

    void rotate_tree(int x)//旋转节点
    {
        int y=e[x].father;
        int mroot=e[y].father;
        pushdown(x); pushdown(y);
        int mrootson=identify(y);
        int yson=identify(x);
        int B=e[x].ch[yson^1];
        connect(B,y,yson); connect(y,x,(yson^1)); connect(x,mroot,mrootson);
        update(y); update(x);
    }

    void splay_tree(int x,int goal)//伸展操作
    {
        for(int t;(t=e[x].father)!=goal;rotate_tree(x))
            if(e[t].father!=goal) rotate_tree(identify(x)==identify(t)? t:x);
        if(goal==0) rot=x;
    }

    int build_tree(int l,int r,int fa)//递归建树
    {
        if(l>r) return 0;
        int mid=l+r>>1;
        int now=++idx;
        e[now].father=fa;
        e[now].ch[0]=e[now].ch[1]=0;
        e[now].recy++,e[now].sum++;
        e[now].v=a[mid];
        e[now].ch[0]=build_tree(l,mid-1,now);
        e[now].ch[1]=build_tree(mid+1,r,now);
        update(now);
        return now;
    }

    int find_tree(int v)
    {
        int now=rot;
        while(1)
        {
            pushdown(now);
            if(v<=e[e[now].ch[0]].sum)
                now=e[now].ch[0];
            else
            {
                v-=e[e[now].ch[0]].sum+e[now].recy;
                if(v<=0) return now;
                now=e[now].ch[1];
            }
        }
        return 0;
    }

    void reverse(int x,int y)
    {
        int l=x-1,r=y+1;
        l=find_tree(l),r=find_tree(r);
        splay_tree(l,0);
        splay_tree(r,l);
        int pos=e[rot].ch[1];
        pos=e[pos].ch[0];
        e[pos].tag^=1;
    }

    void dfs(int now)//输出
    {
        pushdown(now);
        if(e[now].ch[0]) dfs(e[now].ch[0]);
        if(e[now].v!=INF&&e[now].v!=-INF) printf("%d ",e[now].v);
        if(e[now].ch[1]) dfs(e[now].ch[1]);
    }

    void solve()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        a[1]=-INF,a[n+2]=INF;
        for(int i=1;i<=n;i++) a[i+1]=i;
        rot=build_tree(1,n+2,0);
        while(m--)
        {
            int x,y; scanf("%d%d",&x,&y);
            reverse(x+1,y+1);
        }
        dfs(rot);
    }
}S;


int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    S.solve();


	return 0;
}
/*

*/









猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/108282895
今日推荐