zoukankan      html  css  js  c++  java
  • 【[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;
    }
    
  • 相关阅读:
    MySql cmd下的学习笔记 —— 引擎和事务(engine,transaction)
    MySql cmd下的学习笔记 —— 有关视图的操作(algorithm)
    MySql cmd下的学习笔记 —— 有关视图的操作(建立表)
    MySql cmd下的学习笔记 —— 有关常用函数的介绍(数学函数,聚合函数等等)
    MySql cmd下的学习笔记 —— 有关多表查询的操作(多表查询练习题及union操作)
    MySql 在cmd下的学习笔记 —— 有关多表查询的操作(内连接,外连接,交叉连接)
    MySql cmd下的学习笔记 —— 有关子查询的操作(where型,from型,exists型子查询)
    MySql cmd下的学习笔记 —— 有关select的操作(order by,limit)
    剑指Offer--第21题 调整数组顺序使奇数位于偶数前面;
    剑指Offer--和为s的连续正数序列
  • 原文地址:https://www.cnblogs.com/asuldb/p/10205620.html
Copyright © 2011-2022 走看看