并不对劲的线段树套平衡树
最近很对劲的太刀流做的一道题中说树是无向连通无环图,并不对劲的片手流为了反驳他,决定与之针锋相对,就练线段无向连通无环图套平衡无向连通无环图的题。
题意非常简单,就是维护一个数据结构,支持区间排名、区间第k大、单点修改、区间前驱后继这些操作。
主席树+树状数组想必是可以做的,但是并不对劲的人并不想开权值线段树,于是就选择了这种常数极大的做法。
需要注意的是,并不能直接找到区间内排在第k位的数。要二分出答案,然后判断解的排名是否对劲。答案是符合条件的的最大值(因为有的对劲的数并没有出现在数列里)。
并不觉得有什么好说的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define maxn 5000010 #define ls son[u][0] #define rs son[u][1] #define rks son[rk][0] #define m (l+r>>1) #define s0 siz[0]=0 #define Ls (n<<1) #define Rs (n<<1|1) #define inf 2147483647 #define rep(i,x,y) for(register int i=(x);i<=(y);i++) #define dwn(i,x,y) for(register int i=(x);i>=(y);i--) using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(isdigit(ch)==0 && ch!='-')ch=getchar(); if(ch=='-')f=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } inline void write(int x) { int f=0;char ch[20]; if(!x){putchar('0'),putchar('\n');return;} if(x<0){putchar('-');x=-x;} while(x)ch[++f]=x%10+'0',x/=10; while(f)putchar(ch[f--]); putchar('\n'); } int rt[maxn],fa[maxn],son[maxn][3],key[maxn],num[maxn],siz[maxn],a[maxn],cnt,nn,x,y,rank; inline void pu(int u){s0,siz[u]=siz[ls]+siz[rs]+num[u],s0;} inline int res(int k,int f){key[++cnt]=k,fa[cnt]=f,num[cnt]=1;return cnt;} inline int getso(int u){return son[fa[u]][0]!=u;} inline void rot(int u) { int fu=fa[u],ffu=fa[fu],l=getso(u),r=l^1,fl=getso(fu),rson=son[u][r]; fa[rson]=fu,fa[u]=ffu,fa[fu]=u,son[u][r]=fu,son[fu][l]=rson,son[ffu][fl]=u; pu(fu),pu(u); } inline void splay(int u,int k,int pla) { while(fa[u]!=k){int fu=fa[u];if(fa[fu]!=k)rot(getso(u)^getso(fu)?u:fu);rot(u);} if(!k)rt[pla]=u; } inline void fnd(int k,int pla) { int u=rt[pla]; while(son[u][k>key[u]]&&k!=key[u])u=son[u][k>key[u]]; splay(u,0,pla); } inline int nxt(int k,int f,int pla) { fnd(k,pla);int u=rt[pla]; if((key[u]>k&&f)||(key[u]<k&&!f))return u; u=son[u][f]; while(son[u][f^1])u=son[u][f^1]; return u; } inline void ins(int k,int pla) { int lk=nxt(k,0,pla),rk=nxt(k,1,pla); splay(lk,0,pla),splay(rk,lk,pla); if(rks)num[rks]++; else rks=res(k,rk); pu(rks),pu(rk),pu(lk); } inline void sgtr(int n,int l,int r) { rt[n]=res(-inf,0); son[rt[n]][1]=res(inf,rt[n]); pu(son[rt[n]][1]),pu(rt[n]); rep(i,l,r)ins(a[i],n); if(l==r)return; sgtr(Ls,l,m),sgtr(Rs,m+1,r); } inline int rnk(int k,int pla) { int u=rt[pla],rank=0; while(u) { if(key[u]==k){rank+=siz[ls];break;} if(key[u]<k)rank+=siz[ls]+num[u],u=rs; else u=ls; } return rank-1; } inline void del(int k,int pla) { int lk=nxt(k,0,pla),rk=nxt(k,1,pla); splay(lk,0,pla),splay(rk,lk,pla); if(num[rks]>1)num[rks]--; else rks=0; pu(rks),pu(rk),pu(lk); } inline int _1(int n,int l,int r,int k) {//getrank if(x<=l&&r<=y)return rnk(k,n); if(y<l||r<x)return 0; int lans=_1(Ls,l,m,k),rans=_1(Rs,m+1,r,k); return lans+rans; } inline int _2(int k) {//kth int l=0,r=100000001; while(l!=r) { rank=_1(1,1,nn,m)+1; if(rank>k) r=m; else l=m+1; } return l-1; } inline void _3(int n,int l,int r,int k) {//change if(x<l||r<x)return; del(a[x],n),ins(k,n); if(l==r)return; _3(Ls,l,m,k),_3(Rs,m+1,r,k); if(n==1)a[x]=k; } inline int _4(int n,int l,int r,int k) {//prefix if(x<=l&&r<=y)return key[nxt(k,0,n)]; if(y<l||r<x)return -inf; int lans=_4(Ls,l,m,k),rans=_4(Rs,m+1,r,k); return max(lans,rans); } inline int _5(int n,int l,int r,int k) {//suffix if(x<=l&&r<=y)return key[nxt(k,1,n)]; if(y<l||r<x)return inf; int lans=_5(Ls,l,m,k),rans=_5(Rs,m+1,r,k); return min(lans,rans); } int main() { int n,q,f,c;nn=n=read(),q=read(); rep(i,1,n)a[i]=read(); sgtr(1,1,n); while(q--) { f=read(),x=read(),y=read(),c; if(f==1)c=read(),write(_1(1,1,n,c)+1); if(f==2)c=read(),write(_2(c)); if(f==3)_3(1,1,n,y); if(f==4)c=read(),write(_4(1,1,n,c)); if(f==5)c=read(),write(_5(1,1,n,c)); } return 0; }
不写splay这种常数极大的平衡无向连通无环图就不用开O2了。
据说拼命卡常能过。