bzoj3223 文艺平衡树

本文介绍了一种数据结构——文艺平衡树,用于高效处理区间翻转操作。通过文艺平衡树,文章详细阐述了如何维护一个有序数列并进行多次区间翻转,最后输出翻转后的序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3223: Tyvj 1729 文艺平衡树

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 3313   Solved: 1883
[ Submit][ Status][ Discuss]

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 

Input

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n 

Output

 

输出一行n个数字,表示原始序列经过m次变换后的结果 

Sample Input

5 3

1 3

1 3

1 4

Sample Output

4 3 2 1 5

HINT



N,M<=100000

Source

RunID

 UserProblemResultMemoryTimeLanguageCode_LengthSubmit_Time
1538282ksq20133223Accepted5396 kb2576 msC++/Edit2878 B2016-07-08 20:57:17
区间翻转裸题,废话不多说,直接放代码:

#include<cstdio>
#include<iostream>
#define INF 0x3f3f3f3f
#define Key_value ch[ch[root][1]][0]
using namespace std;
bool rev[200100];
int n,m,root,tot,size[200100],key[200100],pre[200100],ch[200100][2];
void NewNode(int &x,int father,int val)
{
    x=++tot;
    size[x]=1;
    key[x]=val;
    pre[x]=father;
}
void Update_Rev(int x)
{
    rev[x]^=1;
    swap(ch[x][0],ch[x][1]);
}
void Push_Up(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void Push_Down(int x)
{
    if(rev[x]){
        Update_Rev(ch[x][0]);
        Update_Rev(ch[x][1]);
        rev[x]=0;
    }
}
void build(int &x,int father,int l,int r)
{
    if(l>r)return;
    int mid=(l+r)>>1;
    NewNode(x,father,mid);
    build(ch[x][0],x,l,mid-1);
    build(ch[x][1],x,mid+1,r);
    Push_Up(x);
}
void Init()
{
    NewNode(root,0,INF);
    NewNode(ch[root][1],root,INF);
    build(Key_value,ch[root][1],1,n);
}
int Get_Kth(int x,int k)
{
    Push_Down(x);//mistaken codes;
    int t=size[ch[x][0]]+1;
    if(t==k)return x;
    if(t>k)return Get_Kth(ch[x][0],k);
    return Get_Kth(ch[x][1],k-t);
}
void Rotate(int x,int kind)
{
    int y=pre[x];
    Push_Down(y);Push_Down(x);
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y])ch[pre[y]][ch[pre[y]][1]==y]=x;//unfixed;
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    Push_Up(y);
}
void Splay(int x,int goal)
{
    Push_Down(x);
    while(pre[x]!=goal){
        if(pre[pre[x]]==goal){
            Push_Down(pre[x]);
            Push_Down(x);
            Rotate(x,ch[pre[x]][0]==x);
        }
        else{
            int y=pre[x];
            int kind=ch[pre[y]][0]==y;
            Push_Down(pre[y]);//mistaken codes&&一遇到向下的操作就Push_Down;
            Push_Down(y);//mistaken codes
            Push_Down(x);//mistaken codes
            if(ch[y][kind]==x){
                Rotate(x,!kind);
                Rotate(x,kind);
            }
            else{
                Rotate(y,kind);
                Rotate(x,kind);
            }
        }
    }
    Push_Up(x);
    if(goal==0)root=x;
}
void Rev(int l,int r)
{
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,r+2),root);
    Update_Rev(Key_value);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void dfs(int x)
{
    if(!x)return;
    Push_Down(x);
    dfs(ch[x][0]);
    if(1<=key[x]&&key[x]<=n)printf("%d ",key[x]);
    dfs(ch[x][1]);
}
int main()
{
    scanf("%d%d",&n,&m);
    Init();
    for(int x,y;m;m--){
        scanf("%d%d",&x,&y);
        Rev(x,y);
    }dfs(root);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值