• 【[HEOI2014]大工程 】


    可能是虚树板子题了

    首先先把虚树建出来,但是这里和那道虚树的入门题不一样,这里所有的询问点都得在虚树里,所以不会存在那种直接不如栈的点

    之后我们考虑一下这个三个要求的东西

    第一个操作我们需要统计虚树上每一条边的贡献,即被多少个点对经过,根据乘法原理显然有((t-sz[x]) imes sz[x] imes w)的贡献

    第二个操作是最大的距离,这不就是直径吗,子树内部最长链和次长链拼一下就好了

    第三个操作是所有点对之间的最小值,因为虚树上有一些点并不是被询问的点,所以不能直接从虚树上选择最小的边,还是需要(dp)一下

    我们用(g[x])表示(x)子树内部的距离(x)最近的标记过得点到(x)的距离,如果(x)被标记了,那么就在这次(dfs)之后把其变成(0),之后像直径那样合并就好了

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define re register
    #define LL long long
    #define maxn 1000005
    #define INF 99999999999
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	re char c=getchar();int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,m,num,__,t,top;
    LL ans,tot,cnt=INF;
    int head[maxn],head_[maxn],a[maxn],st[maxn];
    int Top[maxn],fa[maxn],sum[maxn],deep[maxn],son[maxn],dfn[maxn];
    LL sz[maxn],dp[maxn],f[maxn],to[maxn],g[maxn],to_[maxn];
    struct E {int v,nxt;}e[maxn<<1];
    struct Eg {int v,nxt,w;}e_[maxn<<1];
    inline int cmp(int x,int y){return dfn[x]<dfn[y];}
    inline void add_edge(int x,int y){e[++num].v=y,e[num].nxt=head[x],head[x]=num;}
    inline void add(int x,int y,int z){e_[++num].v=y,e_[num].nxt=head_[x],e_[num].w=z,head_[x]=num;}
    void dfs1(int x)
    {
    	sum[x]=1;
    	int maxx=-1;
    	for(re int i=head[x];i;i=e[i].nxt)
    	if(!deep[e[i].v])
    	{
    		deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
    		dfs1(e[i].v);
    		sum[x]+=sum[e[i].v];
    		if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
    	}
    }
    void dfs2(int x,int topf)
    {
    	Top[x]=topf,dfn[x]=++__;
    	if(!son[x]) return;
    	dfs2(son[x],topf);
    	for(re int i=head[x];i;i=e[i].nxt) if(!Top[e[i].v]) dfs2(e[i].v,e[i].v);
    }
    inline int LCA(int x,int y)
    {
    	while(Top[x]!=Top[y]){if(deep[Top[x]]<deep[Top[y]]) std::swap(x,y);x=fa[Top[x]];}
    	if(deep[x]<deep[y]) return x;return y;
    }
    inline void ins(int x)
    {
    	if(top==1){st[++top]=x;return;}
    	int lca=LCA(x,st[top]);
    	while(top>1&&dfn[st[top-1]]>=dfn[lca]) 
    		add(st[top-1],st[top],deep[st[top]]-deep[st[top-1]]),top--;
    	if(lca!=st[top]) add(lca,st[top],deep[st[top]]-deep[lca]),st[top]=lca;
    	st[++top]=x;
    }
    void Dfs(int x)
    {
    	for(re int i=head_[x];i;i=e_[i].nxt)
    	if(deep[e_[i].v]>deep[x])
    	{
    		Dfs(e_[i].v);
    		sz[x]+=sz[e_[i].v];
    		tot+=sz[e_[i].v]*((LL)t-sz[e_[i].v])*(LL)e_[i].w;
    		if(dp[x]<dp[e_[i].v]+e_[i].w) dp[x]=dp[e_[i].v]+e_[i].w,to[x]=e_[i].v;
    		if(g[x]>g[e_[i].v]+e_[i].w) g[x]=g[e_[i].v]+e_[i].w,to_[x]=e_[i].v;
    	}
    	ans=max(ans,dp[x]);
    	if(f[x]) cnt=min(cnt,g[x]);
    	for(re int i=head_[x];i;i=e_[i].nxt)
    	if(deep[e_[i].v]>deep[x]&&to[x]!=e_[i].v) ans=max(ans,dp[x]+dp[e_[i].v]+(LL)e_[i].w);
    	for(re int i=head_[x];i;i=e_[i].nxt)
    	if(deep[e_[i].v]>deep[x]&&to_[x]!=e_[i].v) cnt=min(cnt,g[x]+g[e_[i].v]+(LL)e_[i].w);
    	if(f[x]) g[x]=0;
    }
    void clear(int x)
    {
    	sz[x]=0;dp[x]=0,to[x]=0;f[x]=0;g[x]=INF;to_[x]=0;
    	for(re int i=head_[x];i;i=e_[i].nxt)
    	if(deep[e_[i].v]>deep[x]) clear(e_[i].v);
    	head_[x]=0;
    }
    int main()
    {
    	n=read();
    	int x,y;
    	for(re int i=1;i<n;i++) {x=read(),y=read();add_edge(x,y),add_edge(y,x);g[i]=INF;}g[n]=INF;
    	deep[1]=1,dfs1(1),dfs2(1,1);
    	m=read();
    	while(m--)
    	{
    		t=read();num=0;ans=0;tot=0;cnt=INF;
    		for(re int i=1;i<=t;i++) a[i]=read(),sz[a[i]]++,f[a[i]]=1;
    		std::sort(a+1,a+t+1,cmp);top=0;
    		int root=LCA(a[1],a[2]);
    		for(re int i=3;i<=t;i++) root=LCA(root,a[i]);
    		st[++top]=root;
    		for(re int i=1;i<=t;i++) if(root!=a[i]) ins(a[i]);
    		while(top) add(st[top-1],st[top],deep[st[top]]-deep[st[top-1]]),top--;
    		Dfs(root);
    		printf("%lld %lld %lld
    ",tot,cnt,ans);
    		clear(root);
    	}
    	return 0;
    }
    
  • 相关阅读:
    2017秋-软件工程第三次作业(3)
    第二周例行总结
    2017秋-软件工程第二次作业
    2017秋-软件工程第一次作业
    ORA-01502: 索引或这类索引的分区处于不可用状态
    Merge into使用详解
    SQL2008中Merge的用法
    system表空间用满解决
    Oracle:ORA-00604: 递归 SQL 级别 1 出现错误
    AIX系统上压缩与解压文件
  • 原文地址:https://www.cnblogs.com/asuldb/p/10205620.html
Copyright © 2020-2023  润新知