BZOJ1146[CTSC2008]网络管理Network
BZOJ1146[CTSC2008]网络管理Network
题面:BZOJ
解析
为什么要用树套树啊?整体二分多好,好写又好想。
还是说一下树套树吧,因为博主做这道题本来是奔着这方法来的,结果却用了离线算法水过。
先考虑不带修改的做法。考虑用dfs入栈出栈序上的主席树,入栈+1,出栈-1,那么每一颗线段树对应的就是它到根的链的权值线段树,那么查询就用lca去除贡献就可以了,复杂度是\(O(nlogn)\)。带修改呢?简单,套个树状数组就行了,复杂度多个log。
至于整体二分,博主他太懒了,不想写了,看代码吧。
代码
#include<cstdio>
#include<iostream>
#define N 80005
#define mid ((l+r)>>1)
#define lc c[u][0]
#define rc c[u][1]
using namespace std;
inline int In(){
char c=getchar(); int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x*ft;
}
int n,m,val[N];
int h[N],e_tot=0;
struct E{ int to,nex; }e[N<<1];
inline void add(int u,int v){
e[++e_tot]=(E){v,h[u]}; h[u]=e_tot;
e[++e_tot]=(E){u,h[v]}; h[v]=e_tot;
}
int d[N],fa[N],sz[N],son[N],top[N];
void dfs1(int u,int pre,int dep){
d[u]=dep; fa[u]=pre; sz[u]=1;
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(v==fa[u]) continue;
dfs1(v,u,dep+1); sz[u]+=sz[v];
if(!son[u]||sz[son[u]]<sz[v]) son[u]=v;
}
}
int dfn[N],dfs_clock=0;
void dfs2(int u,int pre){
top[u]=pre; dfn[u]=++dfs_clock;
if(son[u]) dfs2(son[u],pre);
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
}
}
inline int LCA(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
x=fa[top[x]];
}
return d[x]>d[y]?y:x;
}
int rt=0,T_tot=0,c[N<<1][2],lz[N<<1];
void Update(int L,int R,int C,int l,int r,int& u){
if(!u) u=++T_tot;
if(L<=l&&r<=R){ lz[u]+=C; return; }
if(L<=mid) Update(L,R,C,l,mid,lc);
if(R>mid) Update(L,R,C,mid+1,r,rc);
}
int Query(int G,int l,int r,int u){
if(!u||!G) return 0; if(l==r) return lz[u];
if(G<=mid) return lz[u]+Query(G,l,mid,lc);
else return lz[u]+Query(G,mid+1,r,rc);
}
inline void Add(int x,int C){
Update(dfn[x],dfn[x]+sz[x]-1,C,1,n,rt);
}
inline int Query(int x,int y){
int lca=LCA(x,y);
return Query(dfn[x],1,n,rt)+Query(dfn[y],1,n,rt)-
Query(dfn[lca],1,n,rt)-Query(dfn[fa[lca]],1,n,rt);
}
int qc=0,id[N*3],t1[N*3],t2[N*3],ans[N*3];
struct Q{ int op,i,j,k; }q[N*3];
void Solve(int l,int r,int ql,int qr){
if(ql>qr) return;
if(l==r){ for(int i=ql;i<=qr;++i) ans[id[i]]=l; return; }
int c1=0,c2=0;
for(int i=ql,u;i<=qr;++i){
u=id[i];
if(q[u].op==0){
if(q[u].k>mid) Add(q[u].i,q[u].j),t1[++c1]=u;
else t2[++c2]=u;
}
else{
int S=Query(q[u].i,q[u].j);
if(q[u].k<=S) t1[++c1]=u;
else q[u].k-=S,t2[++c2]=u;
}
}
for(int i=ql,u;i<=qr;++i){
u=id[i];
if(q[u].op==0&&q[u].k>mid)
Add(q[u].i,-q[u].j);
}
for(int i=1;i<=c1;++i) id[ql+i-1]=t1[i];
for(int i=1;i<=c2;++i) id[ql+c1+i-1]=t2[i];
Solve(mid+1,r,ql,ql+c1-1); Solve(l,mid,ql+c1,qr);
}
int main(){
n=In(); m=In();
for(int i=1;i<=n;++i){
val[i]=In();
q[++qc]=(Q){0,i,1,val[i]};
}
for(int i=1;i<n;++i) add(In(),In());
dfs1(1,0,0); dfs2(1,1);
for(int i=1,op,a,b;i<=m;++i){
op=In(); a=In(); b=In();
if(op==0){
q[++qc]=(Q){0,a,-1,val[a]};
q[++qc]=(Q){0,a,1,b};
val[a]=b;
}
else q[++qc]=(Q){1,a,b,op};
}
for(int i=1;i<=qc;++i) id[i]=i;
Solve(-1,1e8,1,qc);
for(int i=1;i<=qc;++i) if(q[i].op==1){
if(ans[i]!=-1) printf("%d\n",ans[i]);
else printf("invalid request!\n");
}
return 0;
}