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

    题目

    P4103 [HEOI2014]大工程

    分析

    虚树(+dp)

    很明显其实题目就是建出虚树,然后对于三问分别考虑:

    第一问就是可以考虑计算每一条边的贡献,也就是左端的 (siz) 和右端的 (siz) 的乘积,就是这条边经过次数。

    二三问就是经典的树的直径的 (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 ll long long
    const int N=2e6+5,t=20,INF=1e9+7;
    int n,m,Ans2,Ans3;
    ll Ans1;
    int head[N],to[N],nex[N],val[N],pre[N],idx;
    int dfn[N],q[N],sta[N],k,top,DFN;
    bool vis[N],flag;
    int Top[N],dep[N],siz[N],fa[N],son[N];
    inline void add(int u,int v){
    	nex[++idx]=head[u];
    	to[idx]=v;
    	pre[idx]=u;
    	head[u]=idx;
    	val[idx]=dep[v]-dep[u];
    	return ;	
    }
    
    void dfs1(int x,int f){
    	siz[x]=1;dep[x]=dep[f]+1;fa[x]=f;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==f) continue;
    		dfs1(y,x);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];}
    int Max1[N],Max2[N],Min1[N],Min2[N];
    void DP(int x,int f){
    	Max1[x]=Max2[x]=-INF,Min1[x]=Min2[x]=INF;siz[x]=0;
    	if(vis[x]) siz[x]++,Min1[x]=Max1[x]=0;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==f) continue;
    		DP(y,x);siz[x]+=siz[y];
    		if(Max1[y]+val[i]>Max1[x]) Max2[x]=Max1[x],Max1[x]=Max1[y]+val[i];
    		else if(Max1[y]+val[i]>Max2[x]) Max2[x]=Max1[y]+val[i];
    		if(Min1[y]+val[i]<Min1[x]) Min2[x]=Min1[x],Min1[x]=Min1[y]+val[i];
    		else if(Min1[y]+val[i]<Min2[x]) Min2[x]=Min1[y]+val[i];  
    	}
    	Ans2=min(Ans2,Min1[x]+Min2[x]);
    	Ans3=max(Ans3,Max1[x]+Max2[x]);
    	return ;
    }
    int clear[N],Cnt;
    void BuildVTree(){
    	sort(q+1,q+k+1,Cmp);
    	top=0,sta[++top]=1;head[1]=0;idx=0;
    	for(int i=1;i<=k;i++){
    		const int x=q[i];
    		if(x==1) continue;head[x]=0;
    		if(top<2){sta[++top]=x;continue;}
    		const int lca=QueryLca(sta[top],x);
    		if(sta[top]==lca){sta[++top]=x;continue;}
    		while(top>1&&dfn[sta[top-1]]>=dfn[lca]) add(sta[top-1],sta[top]),top--;
    		if(sta[top]!=lca) head[lca]=0,add(lca,sta[top]),sta[top]=lca;
    		sta[++top]=x;
    	}
    	while(top>1) add(sta[top-1],sta[top]),top--;
    	return ;
    }
    signed main(){
    	read(n);
    	for(int i=1;i<n;i++){
    		int u,v,w;
    		read(u),read(v);
    		add(u,v),add(v,u);
    	}
    	read(m);
    	dfs1(1,0);dfs2(1,0);
    	while(m--){
    		read(k);flag=false;Ans2=INF,Ans3=-INF;Ans1=0;
    		for(int i=1;i<=k;i++) read(q[i]),vis[q[i]]=true;
    		BuildVTree();
    		DP(1,0);
    		for(int i=1;i<=idx;i++){
    			int x=pre[i],y=to[i];
    			if(dep[x]<dep[y]) swap(x,y);
    			Ans1+=1ll*siz[x]*(k-siz[x])*val[i];
    		}
    		write(Ans1),putchar(' '),write(Ans2),putchar(' '),write(Ans3),putchar('
    ');
    		for(int i=1;i<=k;i++) vis[q[i]]=false;
    	}
    	return 0;
    } 
    

    感受

    计算第一问的方式是一个很好的思路,可以用于路径计算全体贡献的时候,一条一条路径不好计算,那么我们可以考虑算出每一条边的贡献,同样也能达到目的。

  • 相关阅读:
    Porter Stemming Algorithm
    Hook API to detect memory leak
    Are tuples more efficient than lists in Python?
    boost::intrusive_ptr VS boost::shared_ptr
    How Python GC deal with referencecycles?
    LINQ排序数组
    Sublime Text 2 (Version 2.0.1 build 2217) x64 破解注册方法
    GC in C# and Python
    Python中的else
    Managed C++ Destructor
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14737471.html
Copyright © 2011-2022 走看看