zoukankan      html  css  js  c++  java
  • [bzoj3611] [HEOI2014]大工程

    Description

    国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。

    我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。

    在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。

    现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。

    现在对于每个计划,我们想知道:

    1.这些新通道的代价和

    2.这些新通道中代价最小的是多少

    3.这些新通道中代价最大的是多少

    Input

    第一行 n 表示点数。

    接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。

    点从 1 开始标号。 接下来一行 q 表示计划数。

    对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。

    第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

    Output

    输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。

    Sample Input

    10 
    2 1 
    3 2 
    4 1 
    5 2 
    6 4 
    7 5
    8 6 
    9 7 
    10 9 
    5 
    2 
    5 4 
    2 
    10 4 
    2 
    5 2 
    2 
    6 1 
    2 
    6 1 
    

    Sample Output

    3 3 3 
    6 6 6 
    1 1 1 
    2 2 2 
    2 2 2 
    

    Solution

    入门级的(dp)放虚树上变省选难度。。

    建虚树然后无脑(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,char ch) {
    		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]=ch;
    	}
    }
    
    using fast_IO :: read;
    using fast_IO :: write;
    using fast_IO :: flush;
    
    const int maxn = 1e6+10;
    const int N = 2e6+10;
    
    #define ll long long 
    
    int dep[maxn],sz[maxn],dfn[maxn],n;
    
    struct Normal_Tree {
    	int head[maxn],tot,f[maxn][21],dfn_cnt;
    	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) {
    		f[x][0]=fa,dep[x]=dep[fa]+1,dfn[x]=++dfn_cnt,sz[x]=1;
    		for(int i=1;i<=20;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) 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=20;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    		if(x==y) return x;
    		for(int i=20;~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[N],tot,cnt,in[N],tag[N],sta[N],use[N],k,mn[N],mn2[N],mx[N],mx2[N],Min,Max,vis[N];
    	ll ans;
    	struct edge{int to,nxt,w;}e[N<<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) {
    		mn[x]=mn2[x]=1e9,mx[x]=mx2[x]=0;
    		int bo=0;
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=fa) {
    				dfs(e[i].to,x);bo=1;
    				ans+=1ll*e[i].w*(k-tag[e[i].to])*tag[e[i].to];
    				tag[x]+=tag[e[i].to];
    				mx[e[i].to]+=e[i].w;
    				mx2[e[i].to]+=e[i].w;
    				mn[e[i].to]+=e[i].w;
    				mn2[e[i].to]+=e[i].w;
    				//printf("edge :: %d %d %d
    ",x,e[i].to,mn[e[i].to]);
    				if(mx[e[i].to]>mx[x]) mx2[x]=mx[x],mx[x]=mx[e[i].to];
    				else if(mx[e[i].to]>mx2[x]) mx2[x]=mx[e[i].to];
    				if(mn[e[i].to]<mn[x]) mn2[x]=mn[x],mn[x]=mn[e[i].to];
    				else if(mn[e[i].to]<mn2[x]) mn2[x]=mn[e[i].to];
    			}
    		if(mx2[x]) Min=min(Min,mn[x]+mn2[x]),Max=max(Max,mx[x]+mx2[x]);
    		//printf("Dfs :: %d %d %d
    ",x,mn[x],mn2[x]);
    		if(vis[x]) {
    			Min=min(Min,mn[x]);
    			Max=max(Max,mx[x]);
    			mn2[x]=mn[x],mn[x]=0;    // important !!!
    		}
    		if(!bo) mn2[x]=mn[x]=mx[x]=mx2[x]=0;
    	}
    	void solve() {
    		read(k);cnt=0;int top=0,used=0;
    		for(int i=1,x;i<=k;i++) read(x),tag[x]++,in[++cnt]=x,vis[x]=1;
    
    		///    build
    		sort(in+1,in+cnt+1,cmp);cnt=unique(in+1,in+cnt+1)-in-1;
    		sta[++top]=1,use[++used]=1;
    		for(int i=1;i<=cnt;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]-1) {
    				if(pre!=-1) ins(sta[top],pre,dep[pre]-dep[sta[top]]);
    				pre=sta[top],use[++used]=sta[top];top--;
    			}
    			if(pre!=-1) ins(t,pre,dep[pre]-dep[t]);
    			if(sta[top]!=t) sta[++top]=t;
    			sta[++top]=in[i];
    		}
    		int pre=-1;
    		while(top) {
    			if(pre!=-1) ins(sta[top],pre,dep[pre]-dep[sta[top]]);
    			use[++used]=sta[top],pre=sta[top];top--;
    		}
    		///
    		
    		ans=0,Min=1e9,Max=0;dfs(1,0);
    		//printf("%lld %d %d
    ",ans,Min,Max);
    		write(ans,' ');
    		write(Min,' ');
    		write(Max,'
    ');
    		for(int i=1;i<=used;i++) head[use[i]]=tag[use[i]]=vis[use[i]]=0;
    	}
    }VT;
    
    int main() {
    	read(n);for(int i=1,x,y;i<n;i++) read(x,y),T.ins(x,y);
    	dep[0]=-1;T.dfs(1,0);int t;read(t);
    	while(t--) VT.solve();
    	flush();
    	return 0;
    }
    
  • 相关阅读:
    css--兼容写法整理
    vuerouter-7._路由高亮
    vuerouter-6_路由杂项
    vuerouter-5.参数传递
    vuerouter-4.编程式导航
    vuerouter-3.路由嵌套
    正则表达式
    STL容器迭代器失效分析
    coredump
    获取结构体成员偏移量
  • 原文地址:https://www.cnblogs.com/hbyer/p/10218549.html
Copyright © 2011-2022 走看看