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++

  • 相关阅读:
    如何在Ubuntu Server 18.04上安装Microsoft的Procmon
    如何在Ubuntu 20.04上安装Wine 5.0
    如何在Kali Linux 2020中启用SSH服务
    如何在Ubuntu 20.04 LTS Focal Fossa上安装Apache Groovy
    如何使用命令在Ubuntu 20.04 Linux上安装Vmware Tools
    在Ubuntu 20.04 LTS Focal Fossa上安装Zabbix Agent
    hdu 2089 不要62
    hdu 2093 成绩排名
    hdu 2104 hide handkerchief
    leetcode147对链表进行插入排序
  • 原文地址:https://www.cnblogs.com/wzc521/p/11644494.html
Copyright © 2011-2022 走看看