洛谷 P3391 文艺平衡树

题目描述

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

输入输出格式

输入格式:
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数

接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n

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

输入输出样例

输入样例#1:
5 3
1 3
1 3
1 4
输出样例#1:
4 3 2 1 5
说明

N,M<=100000


【分析】
比起上一道题,这题简直菜爆了…
一道模板题,大家可以参考洛谷的题解


【代码】

//bzoj 文艺平衡树 
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 1e9+7 
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
int n,m,sz,opt,root;
int f[mxn],ch[mxn][2],data[mxn],key[mxn],mark[mxn],size[mxn];
inline void clear(int x)
{
    f[x]=ch[x][0]=ch[x][1]=key[x]=mark[x]=0;
}
inline void update(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
inline int get(int x)
{
    if(ch[f[x]][0]==x) return 0;return 1;
}
inline void pushdown(int x)
{
    if(x && mark[x])
    {
        mark[x]=0;
        mark[ch[x][0]]^=1;
        mark[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
    }
}
inline void rotate(int x)
{
    int old=f[x],elder=f[old],which=get(x);
    pushdown(old);pushdown(x);
    ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
    f[old]=x,ch[x][which^1]=old;
    f[x]=elder;
    if(elder) ch[elder][ch[elder][1]==old]=x;
    update(old),update(x);
}
inline void splay(int x,int lastfa)
{
    for(int fa;(fa=f[x])!=lastfa;rotate(x))
      if(f[fa]!=lastfa) rotate(get(x)==get(fa)?fa:x);
    if(!lastfa) root=x;
}
inline int build(int fa,int l,int r)
{
    if(l>r) return 0;
    int mid=l+r>>1,now=++sz;
    key[now]=data[mid],f[now]=fa,mark[now]=0;
    ch[now][0]=build(now,l,mid-1);
    ch[now][1]=build(now,mid+1,r);
    update(now);
    return now;
}
inline void print(int now)
{
    pushdown(now);
    if(ch[now][0]) print(ch[now][0]);
    if(key[now]>-inf && key[now]<inf) printf("%d ",key[now]);
    if(ch[now][1]) print(ch[now][1]);
}
inline int number(int x)
{
    int now=root;
    while(1)
    {
        pushdown(now);
        if(x<=size[ch[now][0]]) now=ch[now][0];
        else
        {
            x=x-size[ch[now][0]]-1;
            if(!x) return now;
            now=ch[now][1];
        }
    }
}
int main()
{
    int i,j,k,x,y;
    scanf("%d%d",&n,&m);
    fo(i,2,n+1) data[i]=i-1;
    data[1]=-inf,data[n+2]=inf;
    root=build(0,1,n+2);
    fo(i,1,m)
    {
        scanf("%d%d",&x,&y);
        x=number(x),y=number(y+2);
        splay(x,0);
        splay(y,x);
        mark[ch[ch[root][1]][0]]^=1;
    }
    print(root);
    return 0;
}
洛谷P1168题目是关于中位数线段树解法的问题。中位数线段树解法可以通过维护两个堆来实现。一个是大根堆,一个是小根堆。每次插入元素时,根据一定的规则来维护这两个堆,使得大根堆的个数在一定情况下比小根堆多1或者相等。大根堆的最后一个元素即为中位数。具体的规则如下: 1. 如果大根堆和小根堆的个数相等,下一次插入的元素一定插入到大根堆。此时判断小根堆的堆顶是否大于当前元素x,如果是,则将小根堆的堆顶元素插入到大根堆,然后将x压入小根堆;否则直接将x压入大根堆。 2. 如果大根堆和小根堆的个数不相等,按照类似的规则进行操作。 通过以上规则,可以实现在每次插入元素时,维护两个堆的平衡,并且保证大根堆的最后一个元素即为中位数。 这种解法的时间复杂度为O(logN),其中N为序列的长度。 #### 引用[.reference_title] - *1* *2* [中位数(洛谷p1168)(堆/树状数组+二分/线段树+二分)](https://blog.csdn.net/qq_45604735/article/details/114382762)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [洛谷 P1168 中位数(权值线段树,离散化)](https://blog.csdn.net/qq_38232157/article/details/127594230)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值