codeforces 671D

luogu鏈接

解法

設f[i]表示覆蓋了i的子樹和i的返祖邊的最小代價,那麼答案就是ison[1]f[i]\sum_{i\in son[1]} f[i],但是f[i]的方案不一定是最終的最優方案,如果某個方案可以向上延伸的更長,即使現在代價比較高,也有可能是最終更優的方案,所以我們需要維護所有有可能成爲答案的方案。然後再給當前點選出一個最小的作爲f。
因爲要選最小值,所以考慮使用小根堆。
轉移的方法:對於xson[y]x\in son[y],從x轉移到y,對於x的小根堆裏的一個方案:如果它不能延伸到y的父親,就需要把它刪了,否則這個方案(設其權值爲val)會對y提供一種權值爲val+zson[y]f[z]f[x]val+\sum_{z\in son[y]} f[z]-f[x],延伸位置不變的方案。
然後對於需要刪除的方案,不需要直接刪除,而是在其成爲堆頂以後再刪除。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int n,m;
struct edge{
	int v,p;
}e[maxn<<1];
int h[maxn],cnt;
inline void add(int a,int b){
	e[++cnt].p=h[a];
	e[cnt].v=b;
	h[a]=cnt;
	e[++cnt].p=h[b];
	e[cnt].v=a;
	h[b]=cnt;
}
typedef pair<int,int> pii;
vector<pii> g[maxn];
int dep[maxn];
ll f[maxn],ans;
struct node{
	pair<ll,int> x;
	ll z;
	int l,r,fa,d;
}t[maxn];
#define fi first
#define se second
inline void add(int x,ll k){
	if(x)t[x].x.fi+=k,t[x].z+=k;
}
inline void pushdown(int x){
	add(t[x].l,t[x].z);
	add(t[x].r,t[x].z);
	t[x].z=0;
}
inline int merge(int x,int y){
	if(!x||!y)return x|y;
	if(t[x].x>t[y].x)swap(x,y);
	if(t[x].z)
	pushdown(x);
	t[x].r=merge(t[x].r,y);
	t[t[x].r].fa=x;
	if(t[t[x].r].d>t[t[x].l].d)swap(t[x].l,t[x].r);
	t[x].d=t[t[x].r].d+1;
	return x;
}
int tot,rt[maxn];
void dfs(int u,int fa){
	dep[u]=dep[fa]+1;
	for(auto o:g[u]){tot++;
		t[tot].x=o,t[tot].d=1;rt[u]=merge(rt[u],tot);
	}
	ll s=0;
	for(int i=h[u];i;i=e[i].p){
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);s+=f[v];
		add(rt[v],-f[v]);rt[u]=merge(rt[u],rt[v]);
	}
	add(rt[u],s);
	while(rt[u]&&dep[t[rt[u]].x.se]>=dep[u]){
		if(t[rt[u]].z)
		pushdown(rt[u]);
		rt[u]=merge(t[rt[u]].l,t[rt[u]].r);
	}
	if(!rt[u]){puts("-1");exit(0);}
	f[u]=t[rt[u]].x.fi;
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		add(x,y);
	}
	for(int i=1;i<=m;i++){
		int x=read(),y=read(),z=read();
		g[x].push_back(pii(z,y));
	}
	dep[1]=1;
	for(int i=h[1];i;i=e[i].p){
		int v=e[i].v;
		dfs(v,1);ans+=f[v];
	}
	printf("%lld\n",ans);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章