1. 程式人生 > >文藝平衡樹 lg3391(splay維護區間入門)

文藝平衡樹 lg3391(splay維護區間入門)

splay是支援區間操作的,先做這道題入個門

大多數操作都和普通splay一樣,就不多解釋了,只解釋一下不大一樣的操作

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'
&&ch<='9'){ w=(w<<3)+(w<<1)+ch-48; ch=getchar(); } return w*f; } int n,m,tot,cnt,root; struct node{ int ch[2],sum,cnt,val,f,rev;//比普通平衡樹多一個lazy tag }st[1000010]; inline void push_up(int p){ st[p].sum=st[st[p].ch[0]].sum+st[st[p].ch[1]].sum+st[p].cnt; } inline
bool identify(int p){ return st[st[p].f].ch[1]==p; } inline void connect(int x,int fa,int son){ st[x].f=fa;st[fa].ch[son]=x;return; } inline void rotate(int x){ int y=st[x].f;int z=st[y].f; int yson=identify(x);int zson=identify(y); int b=st[x].ch[yson^1]; connect(b,y,yson);connect(y,x,(yson
^1));connect(x,z,zson); push_up(y);push_up(x);return; } inline void splay(int x,int goal){ while(st[x].f!=goal){ int y=st[x].f;int z=st[y].f; int yson=identify(x);int zson=identify(y); if(z!=goal){ if(yson==zson) rotate(y); else rotate(x); } rotate(x); } if(!goal) root=x; return; } inline void insert(int x){ int now=root;int f=0; while(st[now].val!=x&&now){ f=now; now=st[now].ch[x>st[now].val]; } if(now){ st[now].cnt++; } else{ tot++;now=tot; if(f){ st[f].ch[x>st[f].val]=now; } st[now].ch[0]=st[now].ch[1]=0; st[now].cnt=st[now].sum=1; st[now].val=x;st[now].f=f; } splay(now,0);return; } inline void push_down(int p){ int ls=st[p].ch[0];int rs=st[p].ch[1]; if(st[p].rev){ swap(st[p].ch[0],st[p].ch[1]); st[st[p].ch[0]].rev^=1; st[st[p].ch[1]].rev^=1; st[p].rev=0; } } inline void find(int x){ int now=root;if(!now) return; while(st[now].val!=x&&st[now].ch[x>st[now].val]){ now=st[now].ch[x>st[now].val]; } splay(now,0);return; } inline int Next(int x,int f){ find(x);int now=root; if(st[now].val<x&&!x) return now; if(st[now].val>x&&x) return now; now=st[now].ch[f]; while(st[now].ch[f^1]) now=st[now].ch[f^1]; return now; } inline int k_th(int x){ int now=root; if(st[now].sum<x) return false; while(true){ push_down(now);//在查詢的時候記得下移標記 int ls=st[now].ch[0]; if(x>st[ls].sum+st[now].cnt){ x-=st[ls].sum+st[now].cnt; now=st[now].ch[1]; } else if(x<=st[ls].sum){ now=ls; } else return now;//這個地方把返回原值改成返回位置 } }inline void rev(int l,int r){ int x=k_th(l-1);int y=k_th(r+1); splay(x,0);splay(y,x); st[st[y].ch[0]].rev^=1; }//翻轉的操作就是將l-1轉到根上,r+1轉到根的右兒子,然後l到r這個區間就是根右兒子的左兒子(比較繞,可以畫個圖想一想 inline void output(int p){ push_down(p); if(st[p].ch[0]) output(st[p].ch[0]); if(st[p].val>=1&&st[p].val<=n) printf("%d ",st[p].val); if(st[p].ch[1]) output(st[p].ch[1]); }//輸出的時候下推一下標記,輸出順序就是二叉樹的順序 int main(){ n=read();m=read();int i,j,k; insert(INF);insert(-INF); for(i=1;i<=n;i++){ insert(i); } while(m--){ int x,y;x=read();y=read(); rev(x+1,y+1); } output(root); return 0; }