zoukankan      html  css  js  c++  java
  • CSP 2019 Day2 T3 树的重心

    题目链接

    solution:

    首先有这样一个结论
    一颗树的重心要么是根节点要么在它重儿子的子树里
    这个结论十分显然在这里就不证明了
    于是我们第一遍(dfs)求出以1节点为根时每个点的重儿子和次重儿子(因为会断掉重儿子的这条边)以及(pr_{u,i})表示从(u)节点开始每次沿重儿子跳(2^i)步跳到的点的位置
    对于第二次(dfs),遍历到(u)节点时,考虑其儿子节点(v),计算将((u,v))断掉后的答案
    (v)为根节点的子树重心,直接用先前处理的(pr)倍增跳同时判断(size)即可
    (u)为根节点的树的重心(相当于换根),从1到(u)沿途修改重儿子值即可,倍增方法相同

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int _=3e5+5;
    int T,N,Tot;
    int Fi[_],Ne[_<<1],To[_<<1];
    int Son[_],Sc_Son[_],H[_][20],Sz[_];
    long long Ans;
    inline int read()
    {
    	int s=0,w=1; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    	return s*w;
    }
    inline void add(int x,int y)
    {
    	Ne[++Tot]=Fi[x];Fi[x]=Tot;To[Tot]=y;
    }
    inline void pre(int x)
    {
    	H[x][0]=Son[x];
    	for(int i=1;i<=18;++i)
    		H[x][i]=H[H[x][i-1]][i-1];
    }
    void dfs1(int u,int fa)
    {
    	int &su=Sz[u],&s=Son[u],&sc=Sc_Son[u];
    	su=1;
    	for(int i=Fi[u];i;i=Ne[i])
    	{
    		int v=To[i],&sv=Sz[v];
    		if(v==fa)continue;
    		dfs1(v,u);
    		su+=sv;
    		if(sv>=Sz[s]){sc=s;s=v;}
    		else if(sv>Sz[sc])sc=v;
    	}
    	pre(u);
    }
    inline void get_ans(int x)
    {
    	if(!Son[x]){Ans+=x;return;}
    	int y=x;
    	for(int i=18;i>=0;--i)
    		if(Sz[x]-Sz[H[y][i]]<Sz[x]/2)y=H[y][i];
    	if(Sz[x]-Sz[y]<=Sz[x]/2&&Sz[Son[y]]<=Sz[x]/2)Ans+=y;
    	y=Son[y];
    	if(Sz[x]-Sz[y]<=Sz[x]/2&&Sz[Son[y]]<=Sz[x]/2)Ans+=y;
    }
    void dfs2(int u,int fa)
    {
    	for(int i=Fi[u];i;i=Ne[i])
    	{
    		int v=To[i];
    		if(v==fa)continue;
    		int &su=Sz[u],&s=Son[u],sv=Sz[v],_su=Sz[u],_s=Son[u];
    		su=N-sv;
    		if(v==Son[u])s=Sc_Son[u];
    		if(fa&&Sz[fa]>Sz[s])s=fa;
    		pre(u);
    		get_ans(u),get_ans(v);
    		dfs2(v,u);
    		su=_su;s=_s;pre(u);
    	}
    }
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		N=read();
    		Ans=Tot=0;fill(Fi+1,Fi+N+1,0);
    		for(int i=1;i<N;++i)
    		{
    			int u=read(),v=read();
    			add(u,v),add(v,u);
    		}
    		fill(Son+1,Son+N+1,0);
    		fill(Sc_Son+1,Sc_Son+N+1,0);
    		dfs1(1,0);dfs2(1,0);
    		printf("%lld
    ",Ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    字符串替换
    字符串查找
    字符串比较
    字节与字符串相互转换
    1365. How Many Numbers Are Smaller Than the Current Number
    1486. XOR Operation in an Array
    1431. Kids With the Greatest Number of Candies
    1470. Shuffle the Array
    1480. Running Sum of 1d Array
    【STM32H7教程】第56章 STM32H7的DMA2D应用之刷色块,位图和Alpha混合
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13924307.html
Copyright © 2011-2022 走看看