【luogu P3391】文艺平衡树

QWQ传送门

要在Splay中修改区间的话,可以先查找size值为l与r+2的两个节点,将一个旋转到根,另一个旋转到根的右儿子上,则要修改的区间就是根的右孩子的左子树

然后直接打翻转标记即可,翻转标记类似于线段树的懒标记,查第k大的时候pushdown,pushdown就是把左儿子,右儿子的位置交换

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,m,tot,root;
struct node
{
    int ch[2],val,size,same,father,mark;
}tree[N];
inline void pushup(int now)
{
    tree[now].size=tree[tree[now].ch[0]].size+1+tree[tree[now].ch[1]].size;
}
inline void pushdown(int now)
{
    if(tree[now].mark)
    {
        tree[tree[now].ch[0]].mark^=1;
        tree[tree[now].ch[1]].mark^=1;
        tree[now].mark=0;
        swap(tree[now].ch[0],tree[now].ch[1]);
    }
}
inline void rotate(int x)
{
    int y=tree[x].father;
    int z=tree[y].father;
    int k=(tree[y].ch[1]==x);//x是y的什么儿子
    tree[z].ch[tree[z].ch[1]==y]=x;    tree[x].father=z;
    tree[y].ch[k]=tree[x].ch[k^1];    tree[tree[x].ch[k^1]].father=y;
    tree[x].ch[k^1]=y;    tree[y].father=x;    
    pushup(y);pushup(x);
}
void splay(int x,int goal)
{
    while(tree[x].father!=goal)
    {
        int y=tree[x].father;
        int z=tree[y].father;
        if(z!=goal)    
            (tree[y].ch[0]==x)^(tree[z].ch[0]==y)?rotate(x):rotate(y);
        rotate(x);
    }        
    if(!goal)    root=x;
}
inline void insert(int x)
{
    int now=root,ff=0;
    while(now)
    {
        ff=now;
        now=tree[now].ch[tree[now].val<x];
    }
    now=++tot;
    tree[now].father=ff; 
    tree[ff].ch[x>tree[ff].val]=now; tree[now].val=x; tree[now].size=1;
    splay(now,0);
}

inline int kth(int x)
{
    int now=root;
    while(19260817)
    {
        pushdown(now);
        if(tree[tree[now].ch[0]].size>=x)    now=tree[now].ch[0];
        else if(x>tree[tree[now].ch[0]].size+1)
        {
            x-=tree[tree[now].ch[0]].size+1;
            now=tree[now].ch[1];
        }
        else return tree[now].val;
    }
}
void write(int now)
{
    pushdown(now);
    if(tree[now].ch[0])    write(tree[now].ch[0]);
    if(tree[now].val>1&&tree[now].val<n+2)    cout<<tree[now].val-1<<" ";
    if(tree[now].ch[1])    write(tree[now].ch[1]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);
    cin>>n>>m;
    for(int i=1;i<=n+2;i++)    insert(i);//1,n+2是虚拟节点
    while(m--)
    {
        int l,r,kl,kr;
        cin>>l>>r;
        kl=kth(l);    
        kr=kth(r+2);
        splay(kl,0);
        splay(kr,kl);
        tree[tree[tree[root].ch[1]].ch[0]].mark^=1;    
    }
    write(root);
    return 0;
}

 

 

 

转载于:https://www.cnblogs.com/Patrickpwq/articles/9750565.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值