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

    [bzoj3611][Heoi2014]大工程

    标签: 虚树 DP


    题目链接

    题解

    发现(sum k与n)是同阶的,很容易想到虚树。
    那么难点就在dp统计上了。
    对于和的话,dp[u]表示u子树内所有边的贡献,那么$ dp[u]=dp[v]+sz[v]×(tot-sz[v])×dis(u,v) ( sz[v]就代表子树内关键点的个数,tot是树中关键点的个数。 最大值我们可以维护一个dpmx[u]代表u到子树中关键点的最长距离。 然后就用)dpmx[u]+dpmx[v]+dis(u,v) $来更新答案。
    最小值也是一样。

    Code

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<set>
    #include<map>
    using namespace std;
    #define ll long long
    #define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
    #define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
    #define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
    #define EREP_g(i,a) for(int i=start_g[(a)];i;i=g[i].next)
    inline int read()
    {
    	int sum=0,p=1;char ch=getchar();
    	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    	if(ch=='-')p=-1,ch=getchar();
    	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    	return sum*p;
    }
    
    const int maxn=1e6+20;
    
    struct node {
    	int v,next;
    };
    
    node e[maxn*2];
    int cnt,start[maxn];
    node g[maxn*2];
    int cnt_g,start_g[maxn];
    
    void addedge(int u,int v)
    {
    	e[++cnt]=(node){v,start[u]};
    	start[u]=cnt;
    }
    
    void addedge_g(int u,int v)
    {
    	g[++cnt_g]=(node){v,start_g[u]};
    	start_g[u]=cnt_g;
    }
    
    int n,deep[maxn],dfn[maxn],times,p[maxn][21];
    
    void dfs(int u,int fa)
    {
    	deep[u]=deep[fa]+1;
    	dfn[u]=++times;
    	p[u][0]=fa;
    	EREP(i,u)
    	{
    		int v=e[i].v;
    		if(v==fa)continue;
    		dfs(v,u);
    	}
    }
    
    void init()
    {
    	n=read();
    	REP(i,1,n-1)
    	{
    		int u=read(),v=read();
    		addedge(u,v);
    		addedge(v,u);
    	}
    	dfs(1,0);
    	for(int j=1;(1<<j)<=n;j++)
    		REP(i,1,n)p[i][j]=p[p[i][j-1]][j-1];
    }
    
    int lca(int u,int v)
    {
    	if(deep[u]<deep[v])swap(u,v);
    	DREP(i,20,0)if(deep[p[u][i]]>=deep[v])u=p[u][i];
    	if(u==v)return u;
    	DREP(i,20,0)if(p[u][i]!=p[v][i])u=p[u][i],v=p[v][i];
    	return p[u][0];
    }
    
    int tot,add[maxn],vis[maxn];
    int top,st[maxn];
    bool cmpx(const int a,const int b)
    {
    	return dfn[a]<dfn[b];
    }
    
    void Make_tree()
    {
    	cnt_g=0;
    	tot=read();
    	REP(i,1,tot)add[i]=read(),vis[add[i]]=1;
    	sort(add+1,add+tot+1,cmpx);
    	top=1;st[0]=0;st[1]=1;
    	REP(i,1,tot)
    	{
    		int u=st[top],v=add[i],Lca=lca(u,v);
    		if(u!=Lca)
    		{
    			top--;
    			while(dfn[st[top]]>dfn[Lca])addedge_g(st[top],st[top+1]),addedge_g(st[top+1],st[top]),top--;
    			addedge_g(Lca,st[top+1]);addedge_g(st[top+1],Lca);
    			if(st[top]!=Lca)st[++top]=Lca;
    		}
    		if(v!=Lca)st[++top]=v;
    	}
    	top--;
    	while(top)addedge_g(st[top],st[top+1]),addedge_g(st[top+1],st[top]),top--;
    }
    
    ll dp_s[maxn];
    int dp_mx[maxn],dp_mn[maxn];
    ll sz[maxn];
    
    void dfs1(int u,int fa)
    {
    	if(vis[u])sz[u]=1;else sz[u]=0;
    	EREP_g(i,u)
    	{
    		int v=g[i].v;
    		if(v==fa)continue;
    		dfs1(v,u);
    		sz[u]+=sz[v];
    	}
    }
    
    int Mx_ans,Mn_ans;
    
    void Dp(int u,int fa)
    {
    	dp_s[u]=0;
    	if(!vis[u])dp_mn[u]=0x3f3f3f3f;else dp_mn[u]=0;
    	if(!vis[u])dp_mx[u]=-0x3f3f3f3f;else dp_mx[u]=0;
    	EREP_g(i,u)
    	{
    		int v=g[i].v,dis=(deep[v]-deep[u]);
    		if(v==fa)continue;
    		Dp(v,u);
    		dp_s[u]+=dp_s[v]+(tot-sz[v])*sz[v]*dis;
    		Mx_ans=max(Mx_ans,dp_mx[v]+dp_mx[u]+dis);
    		dp_mx[u]=max(dp_mx[u],dp_mx[v]+dis);
    		Mn_ans=min(Mn_ans,dp_mn[v]+dp_mn[u]+dis);
    		dp_mn[u]=min(dp_mn[u],dp_mn[v]+dis);
    	}
    	start_g[u]=0;vis[u]=0;
    }
    
    void doing()
    {
    	int q;
    	q=read();
    	REP(i,1,q)
    	{
    		Make_tree();
    		dfs1(1,0);
    		Mx_ans=0;Mn_ans=0x3f3f3f3f;
    		Dp(1,0);
    		printf("%lld %d %d
    ",dp_s[1],Mn_ans,Mx_ans);
    	}
    }
    
    int main()
    {
    	init();
    	doing();
    	return 0;
    }
    
    
    
  • 相关阅读:
    从Java小白到收获BAT等offer,分享我这两年的经验和感悟
    我的Java秋招面经大合集
    从零基础到拿到网易Java实习offer,我做对了哪些事
    设计模式常见面试知识点总结(Java版)
    如何才能够系统地学习Java并发技术?
    这些喜闻乐见的Java面试知识点,你都掌握了吗?
    Java集合类常见面试知识点总结
    用大白话告诉你 :Java 后端到底是在做什么?
    16-使用Selenium模拟浏览器抓取淘宝商品美食信息
    15-分析Ajax请求并抓取今日头条街拍美图
  • 原文地址:https://www.cnblogs.com/gzy-cjoier/p/7623331.html
Copyright © 2011-2022 走看看