zoukankan      html  css  js  c++  java
  • 「Luogu2495」 [SDOI2011]消耗战 虚树

    Luogu P2495 [SDOI2011]消耗战

    problem

    Solution

    苦思冥想稍作思考之后可以得到一个树形DP的方法:
    (w(u,v))表示u,v之间的边的权值,(f[u])表示以(u)为根的子树(不含(u))中所有关键点与根断开的最小代价,则转移方程为:

    [f[u]=egin{cases}w(u,v)& ext{如果v是关键点}\min(w(u,v),dp[v])& ext{如果v非关键点}end{cases} ]

    复杂度为(O(nm)),显然不正确

    对于每次询问可以建立一颗虚树,边权为关键点之间最小的权值

    在这道题中,如果一个关键点(u)的祖先中有关键点(v),那么(u)是不需要加入虚树的,因为(v)一定需要断开,同时也就断开了(u)

    Code

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #define maxn 250005
    using namespace std;
    typedef long long ll;
    
    const ll inf=0x7f7f7f7f7f7f7f7f;
    int n,m,k,h[maxn];
    int dep[maxn],dfn[maxn],sign,prt[maxn][21],key[maxn];
    ll dp[maxn],mnc[maxn][21];
    
    struct edge
    {
    	int u,v,nxt;
    	ll w;
    };
    
    namespace Ori
    {
    	edge g[maxn*2];
    	int head[maxn],ecnt;
    	void eADD(int u,int v,ll w)
    	{
    		g[++ecnt].u=u;g[ecnt].v=v;g[ecnt].w=w;g[ecnt].nxt=head[u];head[u]=ecnt;
    	}
    }
    
    namespace New
    {
    	edge g[maxn];
    	int head[maxn],ecnt;
    	void eADD(int u,int v,ll w)
    	{
    		g[++ecnt].u=u;g[ecnt].v=v;g[ecnt].w=w;g[ecnt].nxt=head[u];head[u]=ecnt;
    	}
    	void Inti()
    	{
    		for(register int i=1;i<=ecnt;++i)
    			g[i].u=g[i].v=g[i].nxt=0,g[i].w=0LL;
    		ecnt=0;
    	}
    }
    
    void dfs(int u,int fa,int depth,ll w)
    {
    	dep[u]=depth,prt[u][0]=fa,mnc[u][0]=w,dfn[u]=++sign;
    	for(register int i=1;(1<<i)<=depth;++i)
    	{
    		prt[u][i]=prt[prt[u][i-1]][i-1];
    		mnc[u][i]=min(mnc[u][i-1],mnc[prt[u][i-1]][i-1]);
    	}
    	for(register int i=Ori::head[u];i;i=Ori::g[i].nxt)
    	{
    		int v=Ori::g[i].v;
    		if(v==fa)
    			continue;
    		dfs(v,u,depth+1,Ori::g[i].w);
    	}
    }
    
    int LCA(int x,int y)
    {
    	if(dep[x]<dep[y])
    		swap(x,y);
    	for(register int i=20;i>=0;--i)
    		if(dep[prt[x][i]]>=dep[y])
    			x=prt[x][i];
    	if(x==y)
    		return x;
    	for(register int i=20;i>=0;--i)
    		if(prt[x][i]!=prt[y][i])
    			x=prt[x][i],y=prt[y][i];
    	return prt[x][0];
    }
    
    bool cmp(const int &a,const int &b)
    {
    	return dfn[a]<dfn[b];
    }
    
    ll getmnc(int u,int v)
    {
    	ll re=inf;
    	if(dep[u]<dep[v])
    		swap(u,v);
    	for(register int i=20;i>=0;--i)
    		if(dep[prt[u][i]]>=dep[v])
    			re=min(re,mnc[u][i]),u=prt[u][i];
    	return re;
    }
    
    int top,stk[maxn];
    void Build()
    {
    	for(register int i=1;i<=k;++i)
    	{
    		if(top==1)
    		{
    			stk[++top]=h[i];
    			continue;
    		}
    		int lca=LCA(stk[top],h[i]);
    		if(lca==stk[top])
    			continue;
    		while(top>1 && dfn[stk[top-1]]>=dfn[lca])
    			New::eADD(stk[top-1],stk[top],getmnc(stk[top-1],stk[top])),--top;
    		if(lca!=stk[top])
    			New::eADD(lca,stk[top],getmnc(lca,stk[top])),stk[top]=lca;
    		stk[++top]=h[i];
    	}
    	while(top-1)
    		New::eADD(stk[top-1],stk[top],getmnc(stk[top],stk[top-1])),--top;
    }
    
    void DP(int u)
    {
    	dp[u]=0;
    	if(!New::head[u])
    		return;
    	for(register int i=New::head[u];i;i=New::g[i].nxt)
    	{
    		int v=New::g[i].v;
    		DP(v);
    		if(key[v])
    			dp[u]+=New::g[i].w;
    		else
    			dp[u]+=min(New::g[i].w,dp[v]);
    	}
    	New::head[u]=0;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(register int i=1;i<n;++i)
    	{
    		int u,v;
    		ll w;
    		scanf("%d%d%lld",&u,&v,&w);
    		Ori::eADD(u,v,w),Ori::eADD(v,u,w);
    	}
    	dfs(1,0,1,inf);
    	scanf("%d",&m);
    	while(m--)
    	{
    		scanf("%d",&k);
    		for(register int i=1;i<=k;++i)
    		{
    			scanf("%d",&h[i]);
    			key[h[i]]=1;
    		}
    		sort(h+1,h+k+1,cmp);
    		top=0;stk[++top]=1;
    		New::Inti();
    		Build();
    		DP(1);
    		printf("%lld
    ",dp[1]);
    		for(register int i=1;i<=k;++i)
    			key[h[i]]=0;
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    网页一屏到底有多大 1024*768 800*600 网页设计大小 网页设计尺寸
    去掉VS2005中水晶报表的登录界面(ZT)
    Visual Studio 2005 IDE 技巧和窍门
    asp.net大页面载入时以进度条显示zt
    从webservice读取string[]至downlist,增加onchange事件,更改相关显示。
    在asp.net Sql server (可以是存储过程)中使用事务回滚
    得到页面所有的form内对象数值——————为一个控件加一个客户端属性
    Agile Web Development 4th ed. Can't mass assign.error
    Ubuntu12.04中安装和配置Java JDK(转)
    Javascript没有块级作用域
  • 原文地址:https://www.cnblogs.com/lizbaka/p/10289894.html
Copyright © 2011-2022 走看看