2022HDU-Multi-University Training Rock Tree

题目链接:https://acm.hdu.edu.cn/contest/problem?cid=1050&pid=1011

大意就是求一个权值和最大的连通块,其直径不超过k。

似乎是个很常见的经典题,dp状态和深度有关,用长链剖分合并一下。

#include<bits/stdc++.h>
#define N 100009
using namespace std;
typedef long long ll;
int head[N],tot,dfn[N],tp[N];
int n,k,son[N],dep[N];
ll tr[N<<2],la[N<<2],a[N],ans,b[N],c[N]; 
inline ll rd(){
	ll x=0;scanf("%lld",&x);
	return x;
}
struct edge{
	int n,to;
}e[N<<1];
inline void pushdown(int cnt){
	la[cnt<<1]+=la[cnt];
	la[cnt<<1|1]+=la[cnt];
	tr[cnt<<1]+=la[cnt];
	tr[cnt<<1|1]+=la[cnt];
	la[cnt]=0;
}
void upd(int cnt,int l,int r,int L,int R,ll x){
	if(l>=L&&r<=R){
		tr[cnt]+=x;
		la[cnt]+=x;
		return;
	}
	int mid=(l+r)>>1;
	if(la[cnt])pushdown(cnt);
	if(mid>=L)upd(cnt<<1,l,mid,L,R,x);
	if(mid<R)upd(cnt<<1|1,mid+1,r,L,R,x);
	tr[cnt]=max(tr[cnt<<1],tr[cnt<<1|1]);
}
ll query(int cnt,int l,int r,int L,int R){
	if(l>=L&&r<=R)return tr[cnt];
	int mid=(l+r)>>1;ll ans=-1e18;
	if(la[cnt])pushdown(cnt);
	if(mid>=L)ans=max(ans,query(cnt<<1,l,mid,L,R));
	if(mid<R)ans=max(ans,query(cnt<<1|1,mid+1,r,L,R));
	return ans;
}
void updmax(int cnt,int l,int r,int x,ll y){
	if(l==r){
		tr[cnt]=max(tr[cnt],y);
		return;
	}
	int mid=(l+r)>>1;
	if(la[cnt])pushdown(cnt); 
	if(mid>=x)updmax(cnt<<1,l,mid,x,y);
	else updmax(cnt<<1|1,mid+1,r,x,y);
	tr[cnt]=max(tr[cnt<<1],tr[cnt<<1|1]);
}
inline void add(int u,int v){
	e[++tot].n=head[u];
	e[tot].to=v;
	head[u]=tot;
}
void dfs(int u,int fa){
	for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
		int v=e[i].to;
		dfs(v,u);
		dep[u]=max(dep[v]+1,dep[u]);
		if(dep[v]>=dep[son[u]])son[u]=v;
	}
}
void dfs2(int u,int fa){
	dfn[u]=++dfn[0];
	if(son[u])dfs2(son[u],u),tp[u]=tp[son[u]];
	else tp[u]=u;
	upd(1,1,n,dfn[u],dfn[tp[u]],a[u]);
	for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
		int v=e[i].to;
		if(v!=son[u]){
			dfs2(v,u);
			int md=min(k-1,dfn[tp[v]]-dfn[v]+1);
			c[0]=a[u]; 
			for(int j=1;j<=md;++j){
				b[j]=query(1,1,n,dfn[v]+j-1,dfn[v]+j-1);
				c[j]=query(1,1,n,dfn[u]+j,dfn[u]+j);
				c[j]=max(c[j],c[j-1]);
				b[j]=max(b[j],b[j-1]);
				updmax(1,1,n,dfn[u]+j,max(b[j]+c[min(k-j-1,j)],b[min(k-j-1,j)]+c[j]));
			}
			int l=md+2;
			int dd=dfn[tp[u]]-dfn[u]+1;
			for(int j=md;j>=1;--j){
				int r=min(k-j,dd);
				if(l<=r){
					upd(1,1,n,dfn[u]+l-1,dfn[u]+r-1,b[j]);
					l=r+1;
				}
			}
		}
	}
	ans=max(ans,query(1,1,n,dfn[u],min(dfn[u]+k-1,dfn[tp[u]])));
}
inline void sol(){
	n=rd();k=rd();
	ans=-1e18;
	for(int i=1;i<=n;++i)a[i]=rd();
	int u,v;
	for(int i=1;i<n;++i){
		u=rd();v=rd();
		add(u,v);add(v,u);
	}
	dfs(1,0);
	dfs2(1,0);
	printf("%lld\n",ans);
	for(int i=1;i<=n*4;++i)tr[i]=la[i]=0;
	for(int i=0;i<=n;++i){
		dfn[i]=tp[i]=head[i]=son[i]=dep[i]=0;
	}
	tot=0;
}
int main(){
//	freopen("1011.in","r",stdin);
	int T=rd();
	while(T--){
		sol();
	}
    return 0;
}

posted @ 2022-08-10 15:45  comld  阅读(30)  评论(0编辑  收藏  举报