[CTSC2008] 網路管理
阿新 • • 發佈:2018-12-11
Description
帶修樹鏈第K大。\((n,q\leq 80000)\)
Solution
據說有很多種方法? 寫了兩種。
- 樹剖套線段樹套平衡樹,外層還需要個二分,複雜度\(O(n\log^4n)\)
- \(dfs\)序上維護樹狀陣列套主席樹,複雜度\(O(n\log^2n)\)
第一種就是比較裸的樹套樹吧,注意二分的\(check(x)\)定義是當答案為\(x\)時這條鏈上是否有至少\(k\)個大於\(x\)的點。 然後平衡樹上查就行了。 試了幾個\(srand\)發現我的生日加上xxx的生日跑的最快... 第二種就可以說一說了 先考慮無修改樹鏈第\(k\)大怎麼求,顯然每個點的主席樹存下了這個點到根的路徑上所有點的權值。然後就是\(sum[x]+sum[y]-sum[lca(x,y)]-sum[fa[lca(x,y)]]\)
Code
\(O(n\log^4n)\)程式碼
這奇怪的變數名奇怪的函式名和奇怪的縮排是我想寫namespace無果造成的,我的碼風還是正常的你們要相信我啊喂
#include<cctype> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using std::min; using std::max; using std::swap; const int N=80005; typedef double db; typedef long long ll; #define pb(A) push_back(A) #define pii std::pair<int,int> #define mp(A,B) std::make_pair(A,B) int root[N<<2]; int head[N],dfn[N],val[N]; int n,m,cnt,fa[N],d[N],tot; int top[N],sze[N],son[N],fs[N]; struct Edge{ int to,nxt; }edge[N<<1]; void add(int x,int y){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt; } int ttot; int delpool[N*20],delcur; int tsze[N*20],tprio[N*20]; int tch[N*20][2],tval[N*20]; void tpushup(int cur){ tsze[cur]=tsze[tch[cur][0]]+tsze[tch[cur][1]]+1; } void trotate(int &x,int d){ int y=tch[x][d],z=tch[y][d^1]; tch[y][d^1]=x;tch[x][d]=z; tpushup(x);tpushup(y);x=y; } int newnode(){ int t=delcur?delpool[delcur--]:++ttot; tch[t][0]=tch[t][1]=tval[t]=tprio[t]=tsze[t]=0;return t; } void tinsert(int &cur,int x){ if(!cur){ cur=newnode(); tsze[cur]=1;tval[cur]=x;tprio[cur]=rand(); return; } int d=x>tval[cur]; tsze[cur]++; tinsert(tch[cur][d],x); if(tprio[tch[cur][d]]<tprio[cur]) trotate(cur,d); } void tremove(int &cur,int x){ if(tval[cur]==x){ if(!tch[cur][0] or !tch[cur][1]){ delpool[++delcur]=cur; cur=tch[cur][0]+tch[cur][1]; return; } if(tprio[tch[cur][0]]<tprio[tch[cur][1]]) trotate(cur,0),tremove(tch[cur][1],x); else trotate(cur,1),tremove(tch[cur][0],x); tpushup(cur); } else{ int d=x>tval[cur]; tremove(tch[cur][d],x); tpushup(cur); } } int trank(int cur,int x){ if(!cur) return 0; if(tval[cur]>=x) return tsze[tch[cur][1]]+1+trank(tch[cur][0],x); else return trank(tch[cur][1],x); } void dfs(int x,int y){ if(!x) return; tinsert(root[y],tval[x]); dfs(tch[x][0],y); dfs(tch[x][1],y); } void build(int cur,int l,int r){ if(l==r){ tinsert(root[cur],val[fs[l]]); return; } int mid=l+r>>1; build(cur<<1,l,mid);build(cur<<1|1,mid+1,r); dfs(root[cur<<1],cur);dfs(root[cur<<1|1],cur); } void modify(int cur,int l,int r,int ql,int qr,int minus,int add){ tremove(root[cur],minus);tinsert(root[cur],add); if(l==r) return; int mid=l+r>>1; if(ql<=mid) modify(cur<<1,l,mid,ql,qr,minus,add); else modify(cur<<1|1,mid+1,r,ql,qr,minus,add); } int query(int cur,int l,int r,int ql,int qr,int c){ if(ql<=l and r<=qr) return trank(root[cur],c); int mid=l+r>>1,ans=0; if(ql<=mid) ans+=query(cur<<1,l,mid,ql,qr,c); if(mid<qr) ans+=query(cur<<1|1,mid+1,r,ql,qr,c); return ans; } int getint(){ int X=0,w=0;char ch=0; while(!isdigit(ch))w|=ch=='-',ch=getchar(); while( isdigit(ch))X=X*10+ch-48,ch=getchar(); return w?-X:X; } void dfs1(int now){ sze[now]=1; for(int i=head[now];i;i=edge[i].nxt){ int to=edge[i].to; if(sze[to]) continue; fa[to]=now;d[to]=d[now]+1; dfs1(to);sze[now]+=sze[to]; son[now]=sze[to]>sze[son[now]]?to:son[now]; } } void dfs2(int now,int low){ dfn[now]=++tot;top[now]=low;fs[tot]=now; if(son[now]) dfs2(son[now],low); for(int i=head[now];i;i=edge[i].nxt){ int to=edge[i].to; if(dfn[to]) continue; dfs2(to,to); } } bool check(int mid,int k,int x,int y){ int ans=0,fir=d[x]+d[y]; while(top[x]!=top[y]){ if(d[top[x]]<d[top[y]]) swap(x,y); ans+=query(1,1,n,dfn[top[x]],dfn[x],mid); x=fa[top[x]]; } if(d[x]<d[y]) swap(x,y); ans+=query(1,1,n,dfn[y],dfn[x],mid); fir-=d[y]*2;fir++; if(fir<k) return 0; if(ans>=k) return 1; return 0; } signed main(){ srand(20020122); n=getint(),m=getint(); for(int i=1;i<=n;i++) val[i]=getint(); for(int i=1;i<n;i++){ int x=getint(),y=getint(); add(x,y);add(y,x); } d[1]=1;dfs1(1);dfs2(1,1);build(1,1,n); while(m--){ int k=getint(),x=getint(),y=getint(); if(!k){ modify(1,1,n,dfn[x],dfn[x],val[x],y); val[x]=y; } else{ int l=0,r=1e8,ans=1e8; while(l<=r){ int mid=l+r>>1; if(check(mid,k,x,y)) ans=mid,l=mid+1; else r=mid-1; } printf(ans==1e8?"invalid request!\n":"%d\n",ans); } } return 0; }
然後是\(O(n\log^2n)\)的
#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
const int N=80005;
typedef double db;
typedef long long ll;
const int M=10000010;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)
int s1[N<<1],s2[N<<1];
int n,m,cnt,tot,val[N],sze[N];
int k[N],x[N],y[N],g[N<<1],len;
int ch[M][2],root[N],f[N][19];
int head[N],sum[M],dfn[N],d[N];
struct Edge{
int to,nxt;
}edge[N<<1];
void add(int x,int y){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
int getint(){
int X=0,w=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
return w?-X:X;
}
void dfs(int now){
sze[now]=1;dfn[now]=++tot;
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(sze[to]) continue;
f[to][0]=now;d[to]=d[now]+1;
for(int j=1;j<=17;j++) f[to][j]=f[f[to][j-1]][j-1];
dfs(to);sze[now]+=sze[to];
}
}
void pushup(int cur){
sum[cur]=sum[ch[cur][0]]+sum[ch[cur][1]];
}
void modify(int &cur,int ql,int c,int l=1,int r=len){
if(!cur) cur=++tot;
if(l==r){sum[cur]+=c;return;}
int mid=l+r>>1;
if(ql<=mid) modify(ch[cur][0],ql,c,l,mid);
else modify(ch[cur][1],ql,c,mid+1,r);
pushup(cur);
}
void add(int x,int y,int z){
while(x<=n)
modify(root[x],y,z),x+=x&-x;
}
int lca(int x,int y){
if(d[x]<d[y]) swap(x,y);
for(int i=17;~i;i--)
if(d[f[x][i]]>=d[y]) x=f[x][i];
if(x==y) return x;
for(int i=17;~i;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int query(int k,int l=1,int r=len){
if(l==r) return l;
int now=0,mid=l+r>>1;
for(int i=1;i<=s1[0];i++) now+=sum[ch[s1[i]][1]];
for(int i=1;i<=s2[0];i++) now-=sum[ch[s2[i]][1]];
if(now>=k){
for(int i=1;i<=s1[0];i++) s1[i]=ch[s1[i]][1];
for(int i=1;i<=s2[0];i++) s2[i]=ch[s2[i]][1];
return query(k,mid+1,r);
} else{
for(int i=1;i<=s1[0];i++) s1[i]=ch[s1[i]][0];
for(int i=1;i<=s2[0];i++) s2[i]=ch[s2[i]][0];
return query(k-now,l,mid);
}
}
void ask(int k,int a,int b){
int c=lca(a,b),dd=f[c][0];s1[0]=s2[0]=0;
if(d[a]+d[b]-d[c]-d[dd]<k) {printf("invalid request!\n");return;}
for(int i=dfn[a];i;i-=i&-i) s1[++s1[0]]=root[i];
for(int i=dfn[b];i;i-=i&-i) s1[++s1[0]]=root[i];
for(int i=dfn[c];i;i-=i&-i) s2[++s2[0]]=root[i];
for(int i=dfn[dd];i;i-=i&-i) s2[++s2[0]]=root[i];
printf("%d\n",g[query(k)]);
}
signed main(){
n=getint(),m=getint();
for(int i=1;i<=n;i++) val[i]=getint(),g[++len]=val[i];
for(int i=1;i<n;i++){
int x=getint(),y=getint();
add(x,y);add(y,x);
}
for(int i=1;i<=m;i++){
k[i]=getint(),x[i]=getint(),y[i]=getint();
if(!k[i]) g[++len]=y[i];
}
std::sort(g+1,g+1+len);len=std::unique(g+1,g+1+len)-g-1;
for(int i=1;i<=n;i++) val[i]=std::lower_bound(g+1,g+1+len,val[i])-g;
for(int i=1;i<=m;i++) if(!k[i]) y[i]=std::lower_bound(g+1,g+1+len,y[i])-g;
d[1]=1;dfs(1);tot=0;
for(int i=1;i<=n;i++) add(dfn[i],val[i],1),add(dfn[i]+sze[i],val[i],-1);
for(int i=1;i<=m;i++){
if(!k[i]) add(dfn[x[i]],val[x[i]],-1),add(dfn[x[i]]+sze[x[i]],val[x[i]],1),val[x[i]]=y[i],add(dfn[x[i]],val[x[i]],1),add(dfn[x[i]]+sze[x[i]],val[x[i]],-1);
else ask(k[i],x[i],y[i]);
} return 0;
}