题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3196
人生中第一棵树套树!
写了一个晚上,成功卡时 9000ms+ 过了!
很要注意数组的大小,因为是树*树的大小嘛!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=2e6+5,nn=5e4+5,inf=1e9;//2e6!! int n,m,tot,siz[maxn],c[maxn][3],fa[maxn],key[maxn],mn,mx,a[nn]; struct N{ int l,r,rt; }t[nn<<2]; void update(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;} void rotate(int x) { int y=fa[x],z=fa[y],d=(c[y][1]==x); if(z!=0)c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][d^1]]=y; c[y][d]=c[x][d^1]; c[x][d^1]=y; update(y); update(x); } void splay(int x,int f)//fa[x]=f { while(fa[x]!=f) { int y=fa[x],z=fa[y]; if(z!=f)// z 而非 y { if((c[y][1]==x)^(c[z][1]==y)) rotate(x); else rotate(y); } rotate(x); } } int find_pre(int x,int v) { if(!x)return 0; if(key[x]>=v) return find_pre(c[x][0],v); else { int y=find_pre(c[x][1],v); if(y)return y; else return x; } } int find_k(int x,int k) { // if(!x)return 0; if(siz[c[x][0]]==k-1)return x; if(siz[c[x][0]]>k-1)return find_k(c[x][0],k); return find_k(c[x][1],k-siz[c[x][0]]-1); } int find_suc(int x,int k)//后继 { if(!x)return 0; if(key[x]<=k)return find_suc(c[x][1],k); else { int y=find_suc(c[x][0],k); if(y)return y; else return x;//说不定就是 x } } int find_Suc(int x,int k)//相等中最小的 { if(!x)return 0; if(key[x]<k)return find_Suc(c[x][1],k); else { int y=find_Suc(c[x][0],k); if(y)return y; else return x;//说不定就是 x } } int query_k(int &x,int k)//查询 k 的排名 { int p=find_Suc(x,k); splay(p,0);//相等中最小的 x=p; return siz[c[p][0]]-1;// -inf } int query(int &x,int k)//二分用 { int p=find_suc(x,k); splay(p,0); x=p; return siz[c[p][0]]-1;// -inf } void insert(int &x,int v) { int p=find_pre(x,v); splay(p,0); int y=find_k(c[p][1],1); splay(y,p);//p tot++; siz[tot]=1; fa[tot]=y; key[tot]=v; c[y][0]=tot; update(y); update(p); x=p;//rt } void del(int &x,int v) { int p=find_pre(x,v); splay(p,0); int y=find_k(c[p][1],2); splay(y,p);//p fa[c[y][0]]=0; c[y][0]=0; update(y); update(p); x=p; } void build(int x,int l,int r) { t[x].l=l; t[x].r=r; t[x].rt=++tot; siz[tot]=2; fa[tot]=0; c[tot][1]=tot+1; key[tot]=-inf; tot++; siz[tot]=1; fa[tot]=tot-1; key[tot]=inf; for(int i=l;i<=r;i++)insert(t[x].rt,a[i]); if(l==r)return; int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); } int query_k(int x,int l,int r,int k)//查询 k 的排名 { if(t[x].l>=l && t[x].r<=r)return query_k(t[x].rt,k);//<=k 的个数 int mid=(t[x].l+t[x].r)>>1,ret=0;//不是 l,r if(mid>=l)ret+=query_k(x<<1,l,r,k);//l,r,无需 l,mid ,因为自带 t[x].l,t[x].r if(mid<r)ret+=query_k(x<<1|1,l,r,k); return ret; } int query(int x,int l,int r,int k)//二分用 //<=mid的个数 { if(t[x].l>=l && t[x].r<=r)return query(t[x].rt,k); int mid=(t[x].l+t[x].r)>>1,ret=0;//不是 l,r if(mid>=l)ret+=query(x<<1,l,r,k); if(mid<r)ret+=query(x<<1|1,l,r,k); return ret; } void modify(int x,int p,int k) { insert(t[x].rt,k); del(t[x].rt,a[p]); if(t[x].l==t[x].r)return;// int mid=(t[x].l+t[x].r)>>1; if(p<=mid)modify(x<<1,p,k); else modify(x<<1|1,p,k); } int query_pre(int x,int l,int r,int k) { if(t[x].l>=l && t[x].r<=r)return key[find_pre(t[x].rt,k)];//返回 key ,因为需要比较 int mid=(t[x].l+t[x].r)>>1,ret=0; if(mid>=l)ret=max(ret,query_pre(x<<1,l,r,k)); if(mid<r)ret=max(ret,query_pre(x<<1|1,l,r,k)); return ret; } int query_suc(int x,int l,int r,int k) { if(t[x].l>=l && t[x].r<=r)return key[find_suc(t[x].rt,k)];//返回 key ,因为需要比较 int mid=(t[x].l+t[x].r)>>1,ret=inf; if(mid>=l)ret=min(ret,query_suc(x<<1,l,r,k)); if(mid<r)ret=min(ret,query_suc(x<<1|1,l,r,k)); return ret; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); mn=min(mn,a[i]); mx=max(mx,a[i]); } build(1,1,n); for(int i=1,op,l,r,k;i<=m;i++) { scanf("%d",&op); if(op!=3)scanf("%d%d%d",&l,&r,&k); if(op==1)printf("%d ",query_k(1,l,r,k)+1);//+1 if(op==2) { int L=mn,R=mx,ans=0; while(L<=R) { int mid=(L+R)>>1; if(query(1,l,r,mid)>=k)ans=mid,R=mid-1;// >也可,因为查询的是 <=mid 的个数 else L=mid+1; } printf("%d ",ans); } if(op==3) { int pos; scanf("%d%d",&pos,&k); modify(1,pos,k); a[pos]=k;//!!! } if(op==4)printf("%d ",query_pre(1,l,r,k)); if(op==5)printf("%d ",query_suc(1,l,r,k)); } return 0; }