P4103 [HEOI2014] Big Project

 

P4103 [HEOI2014] Big Project

Title Description

See: P4103 [HEOI2014] Big Project

Solution

Obviously, it's the boarding question of the virtual tree (I didn't make why I adjusted it for an hour)

Direct virtual tree, DP.

Two or two paths and good demand, as long as the contribution of each side is considered, set upFor the number of key points to ask,For subtreesNumber of key points.

For maximum and minimum paths,

Set upIn order toThe middle distance of the root subtreeDistance from the farthest point,In order toThe middle distance of the root subtreeDistance from the nearest point.

Then there's no more.

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=3e6+50;
const int INF=0x3f3f3f3f;
bool Flag[MAXN];
ll ans1;
int dis[MAXN],ans2,ans3,k,DFN=0,Log[MAXN],a[MAXN];
int stk[MAXN],mn[MAXN],mx[MAXN],size[MAXN],fa[MAXN][21],dep[MAXN],dfn[MAXN],top;
vector<int> e[MAXN],son[MAXN];

inline int read()
{
    int x=0,f=1; char c=getchar();
    while (c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); }
    while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
    return x*f;
}
void add_edge(int u,int v){ son[u].push_back(v); }
void tree_dp(int x,int father)
{
	//cout<<x<<" "<<father<<endl;
	for (int i=0;i<son[x].size();i++) 
	    if (son[x][i]!=father) tree_dp(son[x][i],x);
	mx[x]=Flag[x]?0:-INF,mn[x]=Flag[x]?0:INF,size[x]=Flag[x];
	for (int i=0;i<son[x].size();i++)
		if (son[x][i]!=father) 
		{
			int len=(dep[son[x][i]]-dep[x]);
			ans1+=1ll*size[son[x][i]]*(k-size[son[x][i]])*len;
			if (size[x]>0)
			{
				ans2=max(ans2,mx[x]+mx[son[x][i]]+len); 
				ans3=min(ans3,mn[x]+mn[son[x][i]]+len); 
			}
			mx[x]=max(mx[x],mx[son[x][i]]+len);
			mn[x]=min(mn[x],mn[son[x][i]]+len);
			size[x]+=size[son[x][i]];
		}
	Flag[x]=0;
	son[x].clear();
}
int get_lca(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=Log[dep[x]];i>=0;i--)
	    if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
	if (x==y) return x;
	for (int i=Log[dep[x]];i>=0;i--)
	    if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
void insert(int x)
{
	if (top==1) { stk[++top]=x; return; }
	int lca=get_lca(stk[top],x);
	if (lca==stk[top]) { stk[++top]=x; return; }
	while (top>1&&dfn[stk[top-1]]>=dfn[lca]) add_edge(stk[top-1],stk[top]),top--;
	if (stk[top]!=lca) add_edge(lca,stk[top]),stk[top]=lca;
	stk[++top]=x; 
}
void dfs(int x,int father)
{
	dep[x]=dep[father]+1;
	fa[x][0]=father;
	dfn[x]=++DFN;
	for (int i=1;i<=Log[dep[x]];i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=0;i<e[x].size();i++) 
	if (e[x][i]!=father) dfs(e[x][i],x);
}
int compare(int x,int y){return dfn[x]<dfn[y]; }
int main()
{
	int n=read();
	for (int i=1;i<n;i++) 
	{
		int u=read(),v=read();
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dep[0]=-1,Log[1]=0;
	for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
	dfs(1,0);
	
	int Case=read();
	while (Case--)
	{
		ans1=0,ans2=0,ans3=INF;
		k=read();
		for (int i=1;i<=k;i++) a[i]=read();
		sort(a+1,a+k+1,compare);
		stk[top=1]=1,size[1]=1; 
		for (int i=1;i<=k;i++) 
		{
			Flag[a[i]]=1;
			if (a[i]!=1) insert(a[i]),size[a[i]]=1;
		}
		while (top>1) add_edge(stk[top-1],stk[top]),top--;
		
		
		tree_dp(1,0);
		printf("%lld %d %d\n",ans1,ans3,ans2);
	}
	return 0;
}

Code indentation has been done again...

Posted by vozzek on Sat, 05 Oct 2019 16:06:04 -0700