2019.04.02【SDOI2011】【洛谷P2495】【BZOJ2286】消耗战(虚树)

洛谷传送门

BZOJ传送门


补档计划无题解。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	} 
}
using namespace IO;

using std::cout;
using std::cerr;

cs int N=2.5e5+5;

int n,q;

namespace Tree{
	int last[N],nxt[N<<1],to[N<<1],w[N<<1],ecnt;
	inline void addedge(int u,int v,int val){
		nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
		nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=val;
	}
	
	int fa[N],dep[N],top[N],siz[N],son[N];
	ll mn[N];
	int dfn[N],dfs_clock;
	
	void dfs1(int u){
		siz[u]=1;
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])if(v!=fa[u]){
			dep[v]=dep[u]+1;fa[v]=u;
			mn[v]=std::min(mn[u],(ll)w[e]);
			dfs1(v);siz[u]+=siz[v];
			if(siz[v]>siz[son[u]])son[u]=v;
		}
	}
	
	void dfs2(int u){
		dfn[u]=++dfs_clock;
		if(son[u]){
			top[son[u]]=top[u];
			dfs2(son[u]);
		}
		else return ;
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])if(v!=fa[u]&&v!=son[u]){
			top[v]=v;
			dfs2(v);
		}
	}
	
	inline int LCA(int u,int v){
		while(top[u]!=top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
		return dep[u]<dep[v]?u:v;
	}
	
	inline void build(){
		memset(mn,0x3f,sizeof mn);
		dfs1(1),top[1]=1,dfs2(1);
	}
}

namespace VTree{
	using Tree::dfn;
	using Tree::LCA;
	
	std::vector<int> G[N];
	inline void addedge(int u,int v){
		G[u].push_back(v);
	} 
	
	int a[N];
	int sta[N],top;
	inline bool cmp(cs int &a,cs int &b){
		return dfn[a]<dfn[b];
	}
	
	inline void insert(int u){
		if(top==1)return (void)(sta[++top]=u);
		int lca=LCA(u,sta[top]);
		if(lca==sta[top])return ;
		while(top>1&&dfn[sta[top-1]]>=dfn[lca])addedge(sta[top-1],sta[top]),--top;
		if(lca!=sta[top])addedge(lca,sta[top]),sta[top]=lca;
		sta[++top]=u;
	}
	
	inline ll dp(int u){
		if(!G[u].size())return Tree::mn[u];
		ll res=0;
		for(int re e=G[u].size()-1;~e;--e)
		res+=dp(G[u][e]);
		G[u].clear();
		return std::min(res,Tree::mn[u]);
	}
	
	inline void solve(){
		int k=getint();
		for(int re i=1;i<=k;++i)a[i]=getint();
		std::sort(a+1,a+k+1,cmp);
		sta[top=1]=1;
		for(int re i=1;i<=k;++i)insert(a[i]);
		while(top)addedge(sta[top-1],sta[top]),--top;
		cout<<dp(1)<<"\n";
	}
}

signed main(){
	n=getint();
	for(int re i=1,u,v,w;i<n;++i){
		u=getint(),v=getint(),w=getint();
		Tree::addedge(u,v,w); 
	}
	Tree::build();
	q=getint();
	while(q--)VTree::solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值