对于区间翻转操作,将l-1(代码中建了[1,n+2]个点,故这里为l)先旋转到根,再将r+1(同上,这里为r+2)旋至其右儿子,则r+1的左儿子即我们要翻转的区间
tip:在find时已经更新了rev,所以可以splay
【感觉我的buildtr好恶心啊】
#include<cstdio> #include<cctype> #include<algorithm> #define maxn 100005 using namespace std; int n,m,rt,tr[maxn][2],fa[maxn],siz[maxn],rev[maxn]; inline void read(int &x){ char ch=getchar();x=0;int f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} x*=f; } inline void pushup(int x){siz[x]=siz[tr[x][0]]+siz[tr[x][1]]+1;} inline void buildtr(int l,int r,int f,int &cg){ if(l>r)return; int mid=(l+r)>>1;fa[mid]=f;cg=mid; if(mid>l)buildtr(l,mid-1,mid,tr[mid][0]); if(mid<r)buildtr(mid+1,r,mid,tr[mid][1]); pushup(mid); } inline void pushdown(int x){ if(rev[x]){ swap(tr[x][0],tr[x][1]);rev[x]=0; rev[tr[x][0]]^=1;rev[tr[x][1]]^=1; } } inline int find(int now,int k){ pushdown(now);int sz=siz[tr[now][0]]; if(sz+1==k)return now; if(sz>=k)return find(tr[now][0],k);else return find(tr[now][1],k-sz-1); } inline void rotate(int x,int &root){ int old=fa[x],oldf=fa[old],whicx=tr[old][1]==x; tr[old][whicx]=tr[x][whicx^1];fa[tr[old][whicx]]=old; tr[x][whicx^1]=old;fa[old]=x; fa[x]=oldf; if(old==root)root=x;else {if(oldf)tr[oldf][tr[oldf][1]==old]=x;} pushup(old);pushup(x); } inline void splay(int x,int &root){ while(x!=root){ int y=fa[x],z=fa[y]; if(y!=root)rotate((tr[y][1]==x)==(tr[z][1]==y)?y:x,root); rotate(x,root); } } inline void dfs(int now){ pushdown(now); if(tr[now][0])dfs(tr[now][0]); if(now!=1 && now!=n+2)printf("%d ",now-1); if(tr[now][1])dfs(tr[now][1]); } void rever(int l,int r) { int x=find(rt,l),y=find(rt,r+2); splay(x,rt);splay(y,tr[x][1]); int z=tr[y][0]; rev[z]^=1; } int main(){ read(n);read(m); rt=(n+3)>>1;buildtr(1,rt-1,rt,tr[rt][0]);buildtr(rt+1,n+2,rt,tr[rt][1]);pushup(rt); while(m--){ int x,y;read(x);read(y); rever(x,y); } dfs(rt); }