【BZOJ3223】Tyvj 1729 文艺平衡树【splay】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/87992480

题目链接


  遇到要推lazy标记的一棵splay树,就是要去考虑该怎样的变换了。

  首先就是思路,对于一棵中序遍历的二叉搜索树来说,如果要让一段区间的顺序倒过来,就是要让左右子节点以及每个其下的子节点的左右互换位置就可以改变区间的顺序了。

  那么,我们要如何去推这曾关系呢,发现,如果要再不断的splay中还保留lazy标记的话,就需要在以下操作的时候去保留了,譬如要去splay之前,我们的每一个寻找Kth()的过程要不断的向下的过程中,就需要向下延续lazy标记,当然,输出的时候,也是需要的,我们利用中序遍历来输出的时候也要记住lazy标记的传递。

  该在哪个点上存放第一个lazy标记?这的确是个一开始难到我的问题,我们可以看到,我们假设要放lazy标记的点是一个这段区间的最上面的节点,那么就可以从这个点开始向下推这个lazy,那么,我们就是要确定这个的头了,如何去确定?可以多利用几个点,就是我们可以把点的数目增加到1~N+2,那么有效的就是(i - 1)为有效,所以,我们查询这样的L~R可以由L和R+2来确定中间的L+1~R+1的这些点,然后对它们这个区间的最头直接在lazy上"^1"即可,因为两次的移动就是清零,所以两次"^1"就可以抵消的。

具体代码:


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, M, root, tot;
struct node
{
    int ff, val, ch[2], lazy, size;
    node() { ff = val = ch[0] = ch[1] = lazy = size = 0; }
}t[maxN];
void pushup(int rt) { t[rt].size = t[t[rt].ch[0]].size + t[t[rt].ch[1]].size + 1; }
void pushdown(int rt)
{
    if(t[rt].lazy)
    {
        t[rt].lazy = 0;
        t[t[rt].ch[0]].lazy ^= 1;
        t[t[rt].ch[1]].lazy ^= 1;
        swap(t[rt].ch[0], t[rt].ch[1]);
    }
}
void Rotate(int x)
{
    int y = t[x].ff, z = t[y].ff;
    int k = t[y].ch[1] == x;
    t[z].ch[t[z].ch[1] == y] = x;
    t[x].ff = z;
    t[y].ch[k] = t[x].ch[k^1];
    t[t[x].ch[k^1]].ff = y;
    t[x].ch[k^1] = y;
    t[y].ff = x;
    pushup(y);  pushup(x);
}
void Splay(int x, int goal)
{
    while(t[x].ff != goal)
    {
        int y = t[x].ff, z = t[y].ff;
        if(z != goal) (t[z].ch[0] == y) ^ (t[y].ch[0] == x) ? Rotate(x) : Rotate(y);
        Rotate(x);
    }
    if(!goal) root = x;
}
void insert(int x)
{
    int u = root, ff = 0;
    while(u && t[u].val != x)
    {
        ff = u;
        u = t[u].ch[x>t[u].val];
    }
    u = ++tot;
    if(ff) t[ff].ch[x>t[ff].val] = u;
    t[u].ff = ff;
    t[u].val = x;
    t[u].lazy = 0;
    t[u].size = 1;
    Splay(u, 0);
}
int Kth(int x)
{
    int u = root;
    if(t[u].size < x) return 0;
    while(true)
    {
        pushdown(u);
        int y = t[u].ch[0];
        if(x > t[y].size + 1)
        {
            x -= t[y].size + 1;
            u = t[u].ch[1];
        }
        else
        {
            if(t[y].size >= x) u = y;
            else return u;
        }
    }
}
void work(int l, int r) //我要的区间是l+1~r+1,故最后计算的时候"-1"即可
{
    l = Kth(l); r = Kth(r + 2);
    Splay(l, 0);    Splay(r, l);
    t[t[r].ch[0]].lazy ^= 1;
}
void write(int u)
{
    pushdown(u);
    if(t[u].ch[0]) write(t[u].ch[0]);
    if(t[u].val > 1 && t[u].val <= N + 1) printf("%d ", t[u].val - 1);
    if(t[u].ch[1]) write(t[u].ch[1]);
}
int main()
{
    scanf("%d%d", &N, &M);
    root = tot = 0;
    for(int i=1; i<=N+2; i++) insert(i);
    int l, r;
    while(M--)
    {
        scanf("%d%d", &l, &r);
        work(l, r);
    }
    write(root);
    printf("\n");
    return 0;
}
/*
5 3
1 3
1 3
1 4
*/

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/87992480
今日推荐