nssl 1487.图

D e s c r i p t i o n Description Description

给定一棵大小为 n n n的基环树(一定是奇环),规定一条边的边权等于相邻两个点的点权和
给出所有边的边权,求所有点的点权

数据范围: n ≤ 1 0 5 n\leq 10^5 n105


S o l u t i o n Solution Solution

先找出环(拓扑, d f s dfs dfs,并查集都可),然后求解环上答案,最后 O ( n ) O(n) O(n)递推即可

求解环上答案:
设该环上的点权为 x 1 , x 2 , x 3 … … x h − 1 , x h x_1,x_2,x_3……x_{h-1},x_h x1,x2,x3xh1,xh
然后显然我们有 x 1 + x 2 , x 2 + x 3 … … x h − 1 + x h , x h + x 1 x_1+x_2,x_2+x_3……x_{h-1}+x_h,x_h+x_1 x1+x2,x2+x3xh1+xh,xh+x1的答案
除了最后一项的奇数项减偶数项并求和,可得到 x 1 − x h x_1-x_h x1xh,加上 x h + x 1 x_h+x_1 xh+x1除以二即可得到 x 1 x_1 x1
其它的即可 O ( n ) O(n) O(n)递推

时间复杂度 O ( n ) O(n) O(n)


C o d e Code Code

#include
#include
#include
#include
typedef long long LL;
using namespace std;int n,l[100010],tot,x,y,z,huan,Ans[100010],h,sum,rd[100010];
struct node{int next,to,w;}e[200010];
bool Init[100010],vis[100010],flag;
inline void add(int u,int v,int w)
{
	e[++tot]=(node){l[u],v,w};l[u]=tot;
	e[++tot]=(node){l[v],u,w};l[v]=tot;
	return;
}
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void topsort()//拓扑排序
{
    queue<int>q;
    int y,w;
    for(register int i=1;i<=n;i++) if(!--rd[i]) q.push(i);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(register int i=l[x];i;i=e[i].next) if(!--rd[y=e[i].to]) q.push(y);
    }
    return;
}
inline void dfs(int x,int fa,int dep,int last)//计算环上答案
{
	if(flag) return;
	for(register int i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa||Init[y]==false) continue;
		if(dep%2==0) sum+=(last-e[i].w);//奇数项与偶数项相减
		if(dep==h)
		{
			Ans[huan]=(sum+e[i].w)/2;//计算
			flag=true;
			return;
		}
		if(flag) return;
		dfs(y,x,dep+1,e[i].w);
	}
	return;
}
inline void dfs2(int x)
{
	vis[x]=true;
	for(register int i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(vis[y]) continue;
		Ans[y]=e[i].w-Ans[x];//O(n)递推
		dfs2(y);
	}
	return;
}
signed main()
{
	n=read();
	for(register int i=1;i<=n;i++)
	{
		x=read();y=read();z=read();
		add(x,y,z);
		rd[y]++;rd[x]++;
	}
	topsort();
	for(register int i=1;i<=n;i++) if(rd[i]>0) Init[i]=true,huan=i,h++;
	//huan是环上任意一点,h是环的大小,Init[i]表示i是否在环里
	dfs(huan,-1,1,0);
	dfs2(huan);
	for(register int i=1;i<=n;i++) printf("%d\n",Ans[i]);
}

你可能感兴趣的:(dfs,topsort)