Hihocoder1677

本文介绍了一种使用二叉搜索树实现区间翻转的方法,通过旋转操作将指定区间的节点进行翻转,并最终输出翻转后的字符串。代码中详细展示了如何构建二叉搜索树、执行翻转操作及查询过程。
#include <bits/stdc++.h>


using namespace std;
const int N = 1E5 + 7;
int size[N], key[N], ch[N][2], f[N];
char s[N];
bool rev[N];
int sz, root;
int get(int x) {return x==ch[f[x]][1];}
void pushup(int x){ size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;}
void pushdown(int k)
{
    int &l = ch[k][0], &r = ch[k][1];
    if(rev[k]) {
        swap(l, r);
        rev[k] = 0;
        rev[l] ^= 1, rev[r] ^= 1;
    }
}
void build(int l, int r, int fa)
{
    if(l > r) return ;
    int now = l, last = fa;
    if(l == r) {
        f[now] = last; size[now] = 1;
        ch[last][fa < l] = now;
        return ;
    }
    int mid = (l + r) / 2;
    now = mid;
    build(l, mid-1, mid);
    build(mid+1, r, mid);
    f[mid] = last;  pushup(mid);
    ch[last][mid > fa] = mid;
}
void rotate(int x,int &k)
{
int y = f[x], z = f[y], l, r;
l = get(x), r = !l;
if(y == k) {
        k = x; //可能将ch[z][get(y)]赋值了,因为k是引用.
} else {
        ch[z][get(y)] = x;
    }
f[x] = z; f[y] = x; f[ch[x][r]] = y; //y变为原来x与l相反(r)关系的儿子 **
ch[y][l] = ch[x][r]; ch[x][r] = y; //
pushup(y);pushup(x);
}
void splay(int x,int &k)
{
while(x != k) {
int y = f[x];
if(y != k) {
   rotate((get(x) == get(y)) ? y : x, k);
}
rotate(x, k);
}
}
int findx(int x) //找到排名为X的数
{
    int now = root;
    while(true) {
        pushdown(now);
        if(size[ch[now][0]] >= x) {
            now = ch[now][0];
        } else {
            int tmp = size[ch[now][0]] + 1;
            if(x <= tmp) return now;
            x -= tmp;
            now = ch[now][1];
        }
    }
}
void rever(int l, int r)
{
    int x = findx(l), y = findx(r+2);
    //要操作l+1到r+1这段,把l转到根,r+2转到根的右儿子
    splay(x, root);
    splay(y, ch[x][1]); //引用的是ch[x]的右儿子。
    rev[ch[y][0]] ^= 1;
}
int main()
{
    int n, q;
    scanf("%s%d",s+1,&q);
    n = strlen(s+1);
    build(1, n+2, 0); root = (n + 3) >> 1;


    while(q --) {
        int l, r;
        scanf("%d%d",&l,&r); l ++, r ++;
        rever(l, r);
    }
    for(int i = 2;i <= n + 1;i ++)
printf("%c",s[findx(i)-1]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值