0
点赞
收藏
分享

微信扫一扫

换根dp题目

曾宝月 2022-03-15 阅读 44
c++

题目描述

Tree is a connected acyclic graph. Suppose you are given a tree consisting of nn vertices. The vertex of this tree is called centroid if the size of each connected component that appears if this vertex is removed from the tree doesn't exceed 

.

You are given a tree of size nn and can perform no more than one edge replacement. Edge replacement is the operation of removing one edge from the tree (without deleting incident vertices) and inserting one new edge (without adding new vertices) in such a way that the graph remains a tree. For each vertex you have to determine if it's possible to make it centroid by performing no more than one edge replacement.

输入格式

The first line of the input contains an integer nn ( 2<=n<=4000002<=n<=400000 ) — the number of vertices in the tree. Each of the next n-1n−1 lines contains a pair of vertex indices u_{i}ui​ and v_{i}vi​ ( 1<=u_{i},v_{i}<=n1<=ui​,vi​<=n ) — endpoints of the corresponding edge.

输出格式

Print nn integers. The ii -th of them should be equal to 11 if the ii -th vertex can be made centroid by replacing no more than one edge, and should be equal to 00 otherwise.

题意翻译

给定一颗树,你有一次将树改造的机会,改造的意思是删去一条边,再加入一条边,保证改造后还是一棵树。

请问有多少点可以通过改造,成为这颗树的重心?(如果以某个点为根,每个子树的大小都不大于\dfrac{n}{2}2n​,则称某个点为重心)

输入输出样例

输入 #1复制

3
1 2
2 3

输出 #1复制

1 1 1 

输入 #2复制

5
1 2
1 3
1 4
1 5

输出 #2复制

1 0 0 0 0 
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=4e5+5;
int head[maxn];
int n;
struct node{
    int next,to;
}edge[maxn<<1];
int cnt=0;
void add_edge(int from,int to)
{
    edge[cnt].to=to;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
int f[maxn][2],ff[maxn],s[maxn],pos[maxn],sm[maxn];
void dfs1(int root,int pre)
{
    s[root]=1;
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to!=pre)
        {
            dfs1(to,root);
            int v;
            s[root]+=s[to];
            if(s[to]>s[sm[root]]) sm[root]=to;
            if(s[to]<=n/2) v=s[to];
            else v=f[to][0];
            if(f[root][0]<v)
            {
                f[root][1]=f[root][0];f[root][0]=v;pos[root]=to;
            }
            else if(f[root][1]<v) f[root][1]=v;
        }
    }
}
int ans[maxn];
void dfs2(int root,int pre)
{
    ans[root]=1;
    if(s[sm[root]]>n/2) ans[root]=(s[sm[root]]-f[sm[root]][0]<=n/2);
    else if(n-s[root]>n/2) ans[root]=(n-s[root]-ff[root]<=n/2);
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;int v;
        if(to!=pre)
        {
            if(n-s[root]>n/2) v=ff[root];
            else v=n-s[root];
            ff[to]=max(ff[to],v);
            if(to==pos[root]) ff[to]=max(ff[to],f[root][1]);
            else ff[to]=max(ff[to],f[root][0]);
            dfs2(to,root);
        }
    }
}
int main()
{
    cin>>n;
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++)
    {
        int from,to;cin>>from>>to;
        add_edge(from,to);
        add_edge(to,from);
    }
    dfs1(1,0);
    dfs2(1,0);
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
}

 

题目描述
粉兔的妹子跑了!

于是,粉兔要去找她跑掉的妹子!

粉兔的妹子在福州某中上学 。

福州某中共有 N 个路口 ,编号从 1 到 N。路口之间由 N−1 条双向通行的道路连接,并且任意两个路口之间都是连通的。所有只有一条道路与之连接的路口都是福州某中的出入口。一些路口旁有教学楼。粉兔的妹子每天会从某个入口进去,到某栋教学楼上课,然后再从某个出口离开福州某中 。

由于妹子热爱锻炼身♂体, 所以他总是想使自己一天中走的总路程尽量长。当然,妹子不喜欢走重复的路,所以每天他都不会经过同一条路两次。也就是说,妹子会选择一对出入口使得从到教学楼、出口的距离和最大,并且两条路径不会经过同一条道路。可以证明,在不重复经过同一条道路的前提下,连接两个路口的路径是唯一的,从而它们间的距离也是唯一的。

粉兔通过某种手段控制了福州某中所有教学楼里的监摄像头,并掌握了每天妹子上课的教学楼。现在她想知道,妹子每天分别走了多长的路?

注意两个相同路口的距离为 0。
输入
第一行两个整数 N 和 M,分别表示福州某中的路口个数和总天数。
接下来 N−1 行,每行三个整数,Si,Ti和 Li,代表一条连接路口 Si 和 Ti、长度为 Li的道路 。
接下来 M 行,每一个整数 Ai,代表妹子第 i 天上课的教学楼旁路口编号。
输入数据保证合法。
输出
输出 M 行,分别代表妹子每一天走的路程之和。
样例输入 Copy
8 3
1 2 2
2 3 4
3 4 1
4 5 7
4 6 3
2 7 5
1 8 6
3
6
7
样例输出 Copy
20
16
17
 

const int maxn=1e6+7;

vector<PLL>g[maxn];
ll dp[maxn][2],ans[maxn],n,m;

void dfs1(int u,int fa){
	dp[u][0]=dp[u][1]=0;
	for(auto t:g[u]){
		ll nex=t.first,w=t.second;
		if(nex==fa) continue;
		dfs1(nex,u);
		if(dp[u][0]<dp[nex][0]+w){
			dp[u][1]=dp[u][0];
			dp[u][0]=dp[nex][0]+w;
		}
		else if(dp[u][1]<dp[nex][0]+w){
			dp[u][1]=dp[nex][0]+w;
		}
	}
}

void dfs2(int u,int fa){
	for(auto t:g[u]){
		ll v=t.first,w=t.second;
		if(v==fa) continue;
		if(dp[v][0]+w==dp[u][0]){
			ll d=w+dp[u][1];
			if(dp[v][0]<d){
				dp[v][1]=dp[v][0];
				dp[v][0]=d;
			}
			else if(dp[v][1]<d){
				dp[v][1]=d;
			}
		}
		else{
			ll d=w+dp[u][0];
			if(dp[v][0]<d){
				dp[v][1]=dp[v][0];
				dp[v][0]=d;
			}
			else if(dp[v][1]<d){
				dp[v][1]=d;
			}
		}
		ans[v]=dp[v][0]+dp[v][1];
		dfs2(v,u);
	}
}

int main(){
	n=read,m=read;
	rep(i,1,n-1){
		ll u=read,v=read,w=read;
		g[u].push_back({v,w});
		g[v].push_back({u,w});
	}
	dfs1(1,-1);
	ans[1]=dp[1][0]+dp[1][1];
	dfs2(1,-1);
	while(m--){
		int x=read;
		printf("%lld\n",ans[x]);
	}

	
	
	
	
	
	
	return 0;
}
举报

相关推荐

0 条评论