题目背景
这是一道经典的Splay模板题——文艺平衡树。
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
输入输出格式
输入格式:
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, cdots n-1,n)(1,2,⋯n−1,n) m表示翻转操作次数
接下来m行每行两个数 [l,r][l,r] 数据保证 1 leq l leq r leq n1≤l≤r≤n
输出格式:
输出一行n个数字,表示原始序列经过m次变换后的结果
输入输出样例
输入样例#1:
5 3 1 3 1 3 1 4
输出样例#1:
4 3 2 1 5
说明
n,m≤100000
闲的没事又打了一遍以前打过的SPLAY的模板。。。。
然后发现只要遍历BST的时候就要下传标记!!!
第一次只有find的时候忘了下传标记直接怒T爆零。。。。
所以:到哪都别忘了下传标记!!!!
#include<bits/stdc++.h> #define ll long long #define maxn 100005 using namespace std; int f[maxn],ch[maxn][2]; int siz[maxn],root,le,ri; int n,m,der[maxn],lef,rig; int build(int l,int r,int fa){ if(l>r) return 0; int mid=l+r>>1; f[mid]=fa; ch[mid][0]=build(l,mid-1,mid); ch[mid][1]=build(mid+1,r,mid); siz[mid]=1+siz[ch[mid][0]]+siz[ch[mid][1]]; return mid; } inline int get(int x){ return ch[f[x]][1]==x; } inline void update(int x){ siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1; } inline void pushdown(int x){ if(x&&der[x]){ swap(ch[x][0],ch[x][1]); der[ch[x][0]]^=1,der[ch[x][1]]^=1; der[x]=0; } } inline void rotate(int x){ pushdown(f[x]),pushdown(x); int fa=f[x],ffa=f[fa],tp=get(x); ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa; ch[x][tp^1]=fa,f[fa]=x; f[x]=ffa; if(ffa) ch[ffa][ch[ffa][1]==fa]=x; if(root==fa) root=x; update(fa),update(x); } inline void splay(int x,int d){ for(int fa;(fa=f[x])!=d;rotate(x)) if(f[fa]!=d) rotate((get(fa)==get(x)?fa:x)); } inline int find(int k){ int now=root; while(1){ pushdown(now); if(k<=siz[ch[now][0]]){ now=ch[now][0]; continue; } k-=siz[ch[now][0]]+1; if(k<=0) return now; now=ch[now][1]; } } void print(int x){ pushdown(x); if(ch[x][0]) print(ch[x][0]); if(x!=1&&x!=n+2) printf("%d ",x-1); if(ch[x][1]) print(ch[x][1]); } int main(){ scanf("%d%d",&n,&m); root=build(1,n+2,0); while(m--){ scanf("%d%d",&le,&ri); lef=find(le),splay(lef,0); rig=find(ri+2),splay(rig,root); der[ch[ch[root][1]][0]]^=1; } print(root); return 0; }