给定一棵根为 1,且是黑点的有根树。
每个白点相邻所有的点都是黑点,每个黑点相邻所有的点都是白点。换句话说,你可以从根结点开始,按照深度对每个点黑白染色。
现在对于一条两个端点分别是 u,vu,vu,v 的链,定义其长度为:包含的黑点个数 −-− 包含的白点个数。
请你数一数 长度最大 的链的个数。
输入描述:
全文第一行是 T(1≤T≤105)T(1\le T\le10^5)T(1≤T≤105),表示数据组数;
接下来 TTT 组数据,先输入一行一个正整数表示树的大小 n(1≤n≤2×105,∑n≤3×106)n(1\le n\le2\times10^5,\sum n\le3\times10^6)n(1≤n≤2×105,∑n≤3×106);
接下来输入 n−1n-1n−1 行每行两个正整数 u,v(1≤u,v≤n)u,v(1\le u,v\le n)u,v(1≤u,v≤n) 表示树的一条边。
输出描述:
输出 TTT 行,每行一个整数表示答案。
示例1
输入
1 6 1 2 2 3 3 4 4 5 5 6
输出
6
说明
合法的链分别是:{1},{3},{5},{1,2,3},{3,4,5},{1,2,3,4,5}
思路:题目说给你链,然后给你n-1条链让这些链连接起来成树,问的是lian的个数,只要在连通块上任意找两点就能连在一起,完全当做lian处理即可,把树当作lian连处理。假设涂黑让x加一,涂白让x减一,可以知道在lian上只要是正数时就是最大长度,也就相当于将黑点挑出来让它们连接组合,只要添加一个变量记录当前黑点个数,然后相加,就能得到连接组合的个数。
数字只会出现0与1来回交替时,用异或
vector数组存图(树):vector数组存图是对邻接矩阵的空间优化,有边权时还要创建结构体来配合记录。
仅有两个端点时:
vector<int>v[N];
int l,r;
cin>>l>>r;
v[l].push_back(r);
v[r].push_back(l);
有边权时:
struct node
{
int to;
int w;
}e;
vector<node>G[N];
int l;
cin>>l>>e.to>>e.w;
v[l].push_back(e);
//输出G中的点时,仍需使用node类型来接收
e=G[i][j]//e仍能用
cout<<"from: "<<i<<" to: " <<e.to<<" val: "<<e.w<<endl;
遍历:
void dfs(int son,int fa,int cl)
{
for(auto x:v[son])
{
if(x!=fa) dfs(x,son,cl^1);
}
}
完整代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
//typedef vector<int> vi;
//#define int long long
#define fir first
#define sec second
#define all(x) (x).begin(), (x).end()
#define sz(x) (int)x.size()
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define repd(i, l, r) for (int i = l; i >= r; --i)
#define pb push_back
const int N=2e5+10;
vector<int >v[N];
int ans=0;
int temp;
void dfs(int son,int fa,int cl)
{
if(cl)ans+=++temp;
for(auto x:v[son])
{
if(x!=fa) dfs(x,son,cl^1);
}
}
void solve()
{
int n;
cin>>n;
rep(i,1,n)
{
v[i].clear();
}
ans=0;
temp=0;
rep(i,1,n)
{
int l,r;
cin>>l>>r;
v[l].pb(r);
v[r].pb(l);
}
dfs(1,0,1);
cout<<ans<<endl;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}