1. 程式人生 > >bzoj 4712: 洪水 樹鏈剖分

bzoj 4712: 洪水 樹鏈剖分

       利用待修改樹上兩點間gcd的想法,大概YY出了樹剖的方法。

       然後點開Disscuss,發現了immortalCO(%%%)的做法,發現把自己YY的細節都補充完了,感覺很茲瓷。

       然而他說這是經典問題,對此我對自己狹窄的知識面的可憐的鏼題量感到有點內疚

       不過帶修的獨立集做法還是很茲瓷的!

AC程式碼如下:

#include<bits/stdc++.h>
#define ll long long
#define N 200005
#define M 550005
using namespace std;

int n,tot,dfsclk,fst[N],pnt[N<<1],nxt[N<<1],sz[N],son[N],fa[N],pos[N],id[N],anc[N],ed[N];
ll ans,a[N],b[N],f[N],tx[M],ty[M];
ll read(){
	ll x=0; char cr=getchar();
	while (cr<'0' || cr>'9') cr=getchar();
	while (cr>='0' && cr<='9'){ x=x*10+cr-'0'; cr=getchar(); }
	return x;
}
void add(int x,int y){
	pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;
}
void dfs(int x){
	int i,y; sz[x]=1;
	for (i=fst[x]; i; i=nxt[i]){
		y=pnt[i];
		if (y!=fa[x]){
			fa[y]=x;
			dfs(y); sz[x]+=sz[y];
			if (sz[y]>sz[son[x]]) son[x]=y;
			a[x]+=f[y];
		}
	}
	if (son[x]){
		f[x]=min(a[x],b[x]); a[x]-=f[son[x]];
	} else{
		f[x]=b[x]; a[x]=1000000000000000000ll;
	}
}
void dvd(int x,int tp){
	int i,y; id[pos[x]=++dfsclk]=x; anc[x]=tp;
	if (son[x]) dvd(son[x],tp); else ed[tp]=pos[x];
	for (i=fst[x]; i; i=nxt[i]){
		y=pnt[i];
		if (y!=fa[x] && y!=son[x]) dvd(y,y);
	}
}
void build(int k,int l,int r){
	if (l==r){
		tx[k]=a[id[l]]; ty[k]=b[id[l]]; return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid); build(k<<1|1,mid+1,r);
	tx[k]=tx[k<<1]+tx[k<<1|1]; ty[k]=min(ty[k<<1],ty[k<<1|1]+tx[k<<1]);
}
void mdy(int k,int l,int r,int x){
	if (l==r){
		tx[k]=a[id[x]]; ty[k]=b[id[x]]; return;
	}
	int mid=l+r>>1;
	if (x<=mid) mdy(k<<1,l,mid,x); else mdy(k<<1|1,mid+1,r,x);
	tx[k]=tx[k<<1]+tx[k<<1|1]; ty[k]=min(ty[k<<1],ty[k<<1|1]+tx[k<<1]);
}
void qry(int k,int l,int r,int x,int y){
	if (x<=l && r<=y){
		ans=min(ans+tx[k],ty[k]); return;
	}
	int mid=l+r>>1;
	if (y>mid) qry(k<<1|1,mid+1,r,x,y); if (x<=mid) qry(k<<1,l,mid,x,y);
}
ll getans(int x){	
	ans=0; qry(1,1,n,pos[x],ed[anc[x]]); return ans;
}
int main(){
	n=read();
	int i,x,y;
	for (i=1; i<=n; i++) b[i]=read();
	for (i=1; i<n; i++){
		x=read(); y=read();
		add(x,y); add(y,x);
	}
	dfs(1); dvd(1,1); build(1,1,n);
	int cas=read(); char cr;
	while (cas--){
		cr=getchar(); while (cr<'A' || cr>'Z') cr=getchar();
		x=read();
		if (cr=='C'){
			b[x]+=read();
			for (; x; x=y){
				y=fa[anc[x]]; if (y) a[y]-=getans(anc[x]);
				mdy(1,1,n,pos[x]); if (y) a[y]+=getans(anc[x]);
			}
		} else printf("%lld\n",getans(x));
	}
	return 0;
}


by lych

2016.12.4