树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f3f;
#define LL long long
#define N 20010
struct node
{
int v, nxt;
}e[2 * N];
int head[N], cnt;
void add(int u, int v)
{
e[++cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int n, son[N], ans, flag = 0;
void dfs(int x, int fa)
{
son[x] = 1;
int c = 0;
for (int i = head[x]; i; i = e[i].nxt)
{
int v = e[i].v;
if (v == fa)continue;
dfs(v, x);
son[x] += son[v];
c = max(son[v], c);//儿子节点
}
c = max(c, n - son[x]);//父亲及上面的节点。
if (c < ans)
{
ans = c;
flag = x;
}
else if (c == ans)
{
flag = min(flag, x);
}
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
memset(head, 0, sizeof(head));
cnt = 0, ans = inf;
scanf("%d", &n);
int u, v;
for (int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dfs(1, -1);
cout << flag << " " << ans << endl;
}
return 0;
}
dfs序:每个节点在dfs深度优先遍历中的进出栈的时间序列。
dfs序可以把一棵树区间化,即可以求出每个节点的管辖区间。
剩下用树状数组解决。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 100010
struct node
{
int v,nxt;
}e[N];
int head[N],cnt;
int a[N],n,sum[N];
void add(int u,int v)
{
e[++cnt].v=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int in[N],out[N],id;
void dfs(int x)
{
in[x]=++id;
for(int i=head[x];i;i=e[i].nxt)
{
dfs(e[i].v);
}
out[x]=id;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int d)
{
while(x<=n)
{
sum[x]+=d;
x+=lowbit(x);
}
}
int queue(int x)
{
int ans=0;
while(x>=1)
{
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
scanf("%d",&n);
int u,v,m,x,temp;
char c;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1);
for(int i=1;i<=n;i++)
{
a[i]=1;
update(in[i],1);
}
scanf("%d",&m);
while(m--)
{
cin>>c>>x;
if(c=='C')
{
temp=a[in[x]]^1;
update(in[x],temp-a[in[x]]);
a[in[x]]=temp;
}
else
{
printf("%d\n",queue(out[x])-queue(in[x]-1));
}
}
return 0;
}