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;
    }
    
  • 相关阅读:
    mysql外键(FOREIGNKEY)使用介绍
    MYSQL数据库-约束
    mysql探究之null与not null
    爬虫
    http://blog.csdn.net/w_e_i_/article/details/70766035
    Python 3.5安装 pymysql 模块
    Python 3.5 连接Mysql数据库(pymysql 方式)
    hdu Bone Collector
    hdu City Game
    hdu Largest Rectangle in a Histogram
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13924307.html
Copyright © 2011-2022 走看看