zoukankan      html  css  js  c++  java
  • P2495 [SDOI2011]消耗战

    题目

    P2495 [SDOI2011]消耗战

    一棵树,边有边权,每次给 (m) 个关键点,要求求出使得这 (m) 个点不能从根节点出发到达,需要断掉的边的边权总和的最小值。

    分析

    虚树模板题。

    首先看到特征关键点,还有数据范围的求和符号,很明显是虚树。

    于是我们可以发现题目要求的,我们可以先把虚树建出来,因为如果不在虚树上,那么边和点是没有用的。

    这里要注意的是建立虚树的时候,边权就是当前路径上所有边权的最小值,这个可以倍增也可以树剖随便求一下。

    这里使用的是更简单的办法,也就是直接预处理每个点到根节点的最小值,(dp) 方程很好写,暂不赘述。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;bool f=false;char ch=getchar();
    	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    } 
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define int long long
    const int N=1e6+5,t=20,INF=1e18+7;
    int n,m;
    int head[N],to[N],nex[N],val[N],idx;
    inline void add(int u,int v,int w){
    	nex[++idx]=head[u];
    	to[idx]=v;
    	val[idx]=w;
    	head[u]=idx;
    	return ;	
    }
    int dfn[N],Min[N],dp[N],q[N],sta[N],k,top,DFN;
    bool vis[N];
    int Top[N],dep[N],siz[N],fa[N],son[N];
    void dfs1(int x,int f,int fr){
    	siz[x]=1;dep[x]=dep[f]+1;fa[x]=f;Min[x]=min(Min[f],val[fr]);
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==f) continue;
    		dfs1(y,x,i);siz[x]+=siz[y];
    		if(siz[son[x]]<siz[y]) son[x]=y;
    	}
    	return ;
    }
    void dfs2(int x,int f){
    	if(son[fa[x]]==x) Top[x]=Top[f];
    	else Top[x]=x;
    	dfn[x]=++DFN;
    	if(son[x]) dfs2(son[x],x);
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==f||y==son[x]) continue;
    		dfs2(y,x);	
    	} 
    	return ;
    }
    int QueryLca(int x,int y){
    	while(Top[x]!=Top[y]){
    		if(dep[Top[x]]<dep[Top[y]]) swap(x,y);
    		x=fa[Top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    inline bool Cmp(const int &x,const int &y){return dfn[x]<dfn[y];}
    vector<int> vec[N];
    void BuildVTree(){
    	sort(q+1,q+k+1,Cmp);
    	int cnt=0;sta[++cnt]=1;
        for(int j=1;j<=k;j++){
    		if(q[j]==1)	continue;
    		int x=q[j];
    		if(cnt==1){sta[++cnt]=x;continue;}
    		int lca=QueryLca(sta[cnt],x);
    		if(lca==sta[cnt]){sta[++cnt]=x;continue;}
    		while(cnt>1&&dfn[sta[cnt-1]]>=dfn[lca]) vec[sta[cnt-1]].push_back(sta[cnt]),cnt--;
    		if(lca!=sta[cnt]) vec[lca].push_back(sta[cnt]),sta[cnt]=lca;
    		sta[++cnt]=x;
    	}
    	while(cnt>1) vec[sta[cnt-1]].push_back(sta[cnt]),cnt--;
    	return ;
    }
    void DP(int x){
    	dp[x]=Min[x];
    	if(vis[x]) return ;int res=0;
    	for(auto v:vec[x]) DP(v),res+=dp[v];
    	dp[x]=min(dp[x],res);
    	return ;
    }
    void ReMove(int x){
    	dp[x]=INF;vis[x]=false;
    	for(auto v:vec[x]) ReMove(v);
    	vec[x].clear();
    	return ;
    }
    signed main(){
    	read(n);
    	for(int i=1;i<=n;i++) dp[i]=Min[i]=INF;
    	for(int i=1;i<n;i++){
    		int u,v,w;
    		read(u),read(v),read(w);
    		add(u,v,w),add(v,u,w);
    	}
    	read(m);val[0]=INF,Min[0]=INF;
    	dfs1(1,0,0);dfs2(1,0);
    	while(m--){
    		read(k);
    		for(int i=1;i<=k;i++) read(q[i]),vis[q[i]]=true;
    		BuildVTree();
    		DP(1);
    		write(dp[1]),putchar('
    ');
    		ReMove(1);
    	}
    	return 0;
    } 
    
    
  • 相关阅读:
    使用T4为数据库自动生成实体类
    asp.net 下OnClientClick的妙用
    使用缓存的9大误区(上)
    使用缓存的9大误区(下)
    毕业后的五年拉开大家差距的原因在哪里
    mysql字符集
    redhat网络基础配置
    mysql远程连接问题
    Hibernate hql语句修改部分字段
    JQuery使用方法总结
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14737444.html
Copyright © 2011-2022 走看看