• 洛谷 P5666 树的重心


    洛谷 P5666 树的重心

    https://www.luogu.com.cn/problem/P5666

    Snipaste_2020-06-29_08-58-13.png

    Snipaste_2020-06-29_08-58-25.png

    Tutorial

    https://www.luogu.com.cn/blog/soaring/solution-p5666

    关于树的重心有一条性质,假如(u)不是重心,那么重心一定在(u)的size最大的子树中.

    利用这个性质我们可以利用倍增的思想快速找到重心.即维护(jump(u,i))表示从(u)出发,向重儿子走(2^i)步所到达的节点.

    由于要对于每条边统计,所以用换根dp的思想,在dfs的时候维护以当前节点为根时的(jump)等信息即可.

    Code

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    using namespace std;
    inline char nc() {
    	return getchar();
    	static char buf[100000],*l=buf,*r=buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void read(T &x) {
    	x=0; int f=1,ch=nc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
    	x*=f;
    }
    typedef long long ll;
    const int maxn=299995+50;
    int T,n;
    int head[maxn];
    int anc[maxn],siz[maxn],son[maxn][2];
    int pre[maxn],s[maxn],jump[maxn][20];
    ll an;
    struct edge {
    	int to,nex;
    	edge(int to=0,int nex=0):to(to),nex(nex){}
    }; 
    vector<edge> G;
    inline void addedge(int u,int v) {
    	G.push_back(edge(v,head[u])),head[u]=G.size()-1;
    	G.push_back(edge(u,head[v])),head[v]=G.size()-1;
    }
    void dfs0(int u) {
    	siz[u]=1,son[u][0]=son[u][1]=0;
    	for(int i=head[u];~i;i=G[i].nex) {
    		int v=G[i].to; if(v==anc[u]) continue;
    		anc[v]=u;
    		dfs0(v);
    		siz[u]+=siz[v];
    		if(siz[v]>siz[son[u][0]]) son[u][1]=son[u][0],son[u][0]=v;
    		else if(siz[v]>siz[son[u][1]]) son[u][1]=v;
    	}
    	pre[u]=anc[u],s[u]=siz[u],jump[u][0]=son[u][0];
    	for(int i=1;i<20;++i) jump[u][i]=jump[jump[u][i-1]][i-1];
    }
    inline int check(int x,int r) {
    	if(s[jump[x][0]]>s[r]/2) return 0;
    	return x;
    }
    void sol(int u) {
    	int x=u;
    	for(int i=19;~i;--i) if(s[u]-s[jump[x][i]]<=s[u]/2) x=jump[x][i];
    	an+=check(x,u)+check(pre[x],u);
    }
    void dfs1(int u) {
    	for(int i=head[u];~i;i=G[i].nex) {
    		int v=G[i].to; if(v==anc[u]) continue;
    		pre[u]=pre[v]=0,s[u]=n-siz[v];
    		jump[u][0]=son[u][v==son[u][0]];
    		if(n-siz[u]>siz[jump[u][0]]) jump[u][0]=anc[u];
    		for(int j=1;j<20;++j) jump[u][j]=jump[jump[u][j-1]][j-1];
    		sol(u),sol(v);
    		pre[u]=v;
    		dfs1(v);
    	}
    	pre[u]=anc[u],s[u]=siz[u],jump[u][0]=son[u][0];
    	for(int i=1;i<20;++i) jump[u][i]=jump[jump[u][i-1]][i-1];
    }
    int main() {
    	read(T);
    	for(int kase=1;kase<=T;++kase) {
    		read(n);
    		memset(head,-1,sizeof(head)),G.clear();
    		for(int i=1;i<n;++i) {
    			int u,v; read(u),read(v);
    			addedge(u,v);
    		}
    		an=0;
    		dfs0(1);
    		dfs1(1);
    		printf("%lld
    ",an);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    中值滤波与图像锐化
    空间域图像增强
    图像的几何变换
    Fourier分析应用
    Gale-Shapley算法
    有理数与无限循环小数
    线性可分支持向量机
    拉格朗日乘子法+KKT条件
    点到平面的距离
    BP神经网络
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13206081.html
Copyright © 2020-2023  润新知