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

    Description

    在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

    侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。

    Input

    第一行一个整数n,代表岛屿数量。

    接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。

    第n+1行,一个整数m,代表敌方机器能使用的次数。

    接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。

    Output

    输出有m行,分别代表每次任务的最小代价。

    Sample Input

    10
    1 5 13
    1 9 6
    2 1 19
    2 4 8
    2 3 91
    5 6 8
    7 5 4
    7 8 31
    10 7 9
    3
    2 10 6
    4 5 7 8 3
    3 9 4 6
    

    Sample Output

    12
    32
    22
    

    Solution

    虚树入门题。

    注意如果一个点被标记了,它子树下也有被标记的点,下面的点可以删掉,然后dp。

    #include<bits/stdc++.h>
    using namespace std;
    
    #ifdef ONLINE_JUDGE
    #define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++)
    #endif
    
    namespace fast_IO {
    	char buf[1<<21],*p1=buf,*p2=buf;
    
    	template <typename T> inline void read(T &x) {
    		x=0;T f=1;char ch=getchar();
    		for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    		for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    	}
    	template <typename T,typename... Args> inline void read(T& x,Args& ...args) {
    		read(x),read(args...);
    	}
    
    	char buf2[1<<21],a[80];int p,p3=-1;
    
    	inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;}
    	template <typename T> inline void write(T x) {
    		if(p3>(1<<20)) flush();
    		if(x<0) buf2[++p3]='-',x=-x;
    		do {a[++p]=x%10+48;} while(x/=10);
    		do {buf2[++p3]=a[p];} while(--p);
    		buf2[++p3]='
    ';flush();
    	}
    	template <typename T,typename... Args> inline void write(T x,Args ...args) {
    		write(x),write(args...);
    	}
    }
    
    using fast_IO :: read;
    using fast_IO :: write;
    using fast_IO :: flush;
    
    #define ll long long 
    
    const int maxn = 2.5e5+10;
    const int inf = 1e9;
    
    int mn[maxn],dfn[maxn],n,sz[maxn];
    ll f[maxn];
    
    struct Normal_Tree {
    	int head[maxn],tot,dfn_cnt,f[maxn][20],dep[maxn];
    	struct edge{int to,nxt,w;}e[maxn<<1];
    	void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
    	void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
    	void dfs(int x,int fa) {
    		dfn[x]=++dfn_cnt;f[x][0]=fa;dep[x]=dep[fa]+1;sz[x]=1;
    		for(int i=1;i<=17;i++) f[x][i]=f[f[x][i-1]][i-1];
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=fa) mn[e[i].to]=min(mn[x],e[i].w),dfs(e[i].to,x),sz[x]+=sz[e[i].to];
    	}
    	int lca(int x,int y) {
    		if(dep[x]<dep[y]) swap(x,y);
    		for(int i=17;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    		if(x==y) return x;
    		for(int i=17;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    		return f[x][0];
    	}
    }T;
    
    int cmp(int x,int y) {return dfn[x]<dfn[y];}
    
    struct Virtual_Tree {
    	int head[maxn],tot,sta[maxn],use[maxn],in[maxn],top,used,a[maxn];
    	struct edge{int to,nxt;}e[maxn<<1];
    	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    	void ins(int u,int v) {add(u,v),add(v,u);}
    	void dfs(int x,int fa) {
    		int bo=1;
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=fa) dfs(e[i].to,x),f[x]+=min((ll)mn[e[i].to],f[e[i].to]),bo=0;
    		if(bo) f[x]=mn[x];
    		//printf("Dfs:%d %d
    ",x,f[x]);
    	}
    	void solve() {
    		int k;read(k);top=used=0;
    		for(int i=1;i<=k;i++) read(a[i]);
    		sort(a+1,a+k+1,cmp);int p=0;
    		for(int i=1;i<=k;i++)
    			if(dfn[a[i]]>dfn[in[p]]+sz[in[p]]-1) in[++p]=a[i];
    		k=p;
    		sta[++top]=1;use[++used]=1;
    		for(int i=1;i<=k;i++) {
    			if(in[i]==1) continue;
    			int t=T.lca(in[i],sta[top]),pre=-1;
    			while(dfn[sta[top]]>dfn[t]&&dfn[sta[top]]<dfn[t]+sz[t]) {
    				if(pre!=-1) ins(sta[top],pre);
    				pre=sta[top];use[++used]=sta[top];top--;
    			}
    			if(pre!=-1) ins(t,pre);
    			if(sta[top]!=t) sta[++top]=t;
    			sta[++top]=in[i];
    		}
    		int pre=-1;
    		while(top) {
    			if(pre!=-1) ins(sta[top],pre);
    			pre=sta[top],use[++used]=sta[top];top--;
    		}
    		dfs(1,0),write(f[1]);
    		for(int i=1;i<=used;i++) head[use[i]]=0,f[use[i]]=0;
    		tot=0;
    	}
    }VT;
    
    int main() {
    	read(n);
    	for(int i=1,x,y,z;i<n;i++) read(x,y,z),T.ins(x,y,z);
    	for(int i=1;i<=n;i++) mn[i]=inf,f[i]=0;T.dfs(1,0);mn[1]=0;
    	int t;read(t);
    	while(t--) VT.solve();
    	flush();
    	return 0;
    }
    
  • 相关阅读:
    未将对象引用设置到对象的实例--可能出现的问题总结
    Unity3d物体模型(实现旋转缩放平移自动旋转)
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java中环境变量PATH与CLASSPATH的区别
    Java中环境变量PATH与CLASSPATH的区别
    Java中环境变量PATH与CLASSPATH的区别
  • 原文地址:https://www.cnblogs.com/hbyer/p/10216492.html
Copyright © 2011-2022 走看看