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;
}


posted @ 2019-03-18 21:26  pkh68  阅读(160)  评论(0编辑  收藏  举报