zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:Walk(树的直径+数学)

    题目描述

      给定一棵$n$个节点的树,每条边的长度为$1$,同时有一个权值$w$。定义一条路径的权值为路径上所有边的权值的最大公约数。现在对于任意$iin [1,n]$,求树上所有长度为$i$的简单路径中权值最大的是多少。如果不存在长度为$i$的路径,则第$i$行输出$0$。


    输入格式

    第一行,一个整数$n$,表示树的大小。
    接下来$n-1$行,每行三个整数$u,v,w$,表示$u,v$间存在一条权值为$w$的边。


    输出格式

    对于每种长度,输出一行,表示答案。


    样例

    样例输入:

    3
    1 2 3
    1 3 9

    样例输出:

    9
    3
    0


    数据范围与提示

    对于$30\%$的数据,$nleqslant 1,000$。
    对于额外$30\%$的数据,$wleqslant 100$。
    对于$100\%$的数据,$nleqslant 4 imes 10^5,1leqslant u,vleqslant n,wleqslant 10^6$。


    题解

    直接处理很难,考虑如何转化问题。

    将问题反过来,也就是转化为对于每一个$gcd$,将其倍数的边建树,建成一棵森林,求树的直径,对于一样的直径,我们只要那棵$gcd$最大的树的$gcd$就好了。

    时间复杂度:$Theta(nsqrt{w})$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct node{int nxt,to,w;}e[800000];
    int head[400001],cnt;
    int n;
    int mxw;
    int ans[400001];
    int mx[400001];
    bool vis[400001];
    int sta[800001];
    vector<pair<int,int>>tr[1000001];
    void pre_work()
    {
    	for(int i=1;i<=sta[0];i++)
    	{
    		head[sta[i]]=0;
    		vis[sta[i]]=0;
    	}
    	cnt=sta[0]=mxw=0;
    }
    void add(int x,int y)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	head[x]=cnt;
    }
    void dfs(int x,int fa)
    {
    	mx[x]=0;
    	vis[x]=1;
    	int maxn=0;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(e[i].to!=fa)dfs(e[i].to,x);
    	for(int i=head[x];i;i=e[i].nxt)
    		if(e[i].to!=fa)
    			if(mx[x]<=mx[e[i].to])
    			{
    				maxn=mx[x];
    				mx[x]=mx[e[i].to]+1;
    			}
    			else if(maxn<=mx[e[i].to])maxn=mx[e[i].to]+1;
    	mxw=max(mxw,mx[x]+maxn);
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<n;i++)
    	{
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		tr[w].push_back(make_pair(u,v));
    	}
    	for(int i=1;i<=1000000;i++)
    	{
    		pre_work();
    		for(int j=i;j<=1000000;j+=i)
    		{
    			for(int k=0;k<tr[j].size();k++)
    			{
    				add(tr[j][k].first,tr[j][k].second);
    				add(tr[j][k].second,tr[j][k].first);
    				sta[++sta[0]]=tr[j][k].first;
    				sta[++sta[0]]=tr[j][k].second;
    			}
    		}
    		for(int j=1;j<=sta[0];j++)
    			if(!vis[sta[j]])
    				dfs(sta[j],0);
    		ans[mxw]=i;
    	}
    	for(int i=n;i;i--)ans[i]=max(ans[i],ans[i+1]);
    	for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Codeforces Round #613 (Div. 2)
    Codeforces Round #575 (Div. 3)
    Codeforces Round #572 (Div. 2)
    CodeCraft-20 (Div. 2)
    Educational Codeforces Round 76 (Rated for Div. 2)
    欧拉筛法模板代码
    【Android Studio】安卓开发初体验3.1——UI设计之常用控件
    【kotlin】adapterPosition方法返回-1 无法获取位置
    【洛谷】P1009 阶乘之和——高精度算法
    【Android Studio】安卓开发初体验2——Activity
  • 原文地址:https://www.cnblogs.com/wzc521/p/11644494.html
Copyright © 2011-2022 走看看