题意: 给出一棵树,可以给边加任意权值,使任意两叶子之间通路的边权异或和为0,问最少和最多的边权的种类数
思路: 有点猜的,觉得最小的情况要不是1要不是3,1的情况是任意两叶子通路均为偶数个边,其余都是3
最大的情况是看每个叶子到树干的分叉的那个长度如果是1,就把这个节点打个标记,有多个长度为1的分叉在同一个点就只能算一次,(如果长度超过1必可以有不重复的组合出来,
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> g[N];
int n;
int solveMax() {
vector<int> q;
q.clear();
for(int i = 1; i <= n; ++ i) {
if(g[i].size() == 1) {
q.push_back(i);
}
}
set<int> se;
se.clear();
int tot = 0;
int siz = q.size();
for(int i = 0; i < siz; ++ i) {
int p = q[i];
int nxt = g[p][0];
if(g[nxt].size() > 2) {
se.insert(nxt);
tot ++;
}
}
return n - 1 - tot + se.size();
}
int solveMin() {
vector<int> q;
q.clear();
for(int i = 1; i <= n; ++ i) {
if(g[i].size() == 1) {
q.push_back(i);
}
}
int s = q[0];
queue<int> que;
while(!que.empty()) que.pop();
bool vis[N] = {
0};
int dep[n] = {
0};
que.push(s);
dep[s] = 0;
while(!que.empty()) {
int tmp = que.front();
que.pop();
int siz = g[tmp].size();
for(int i = 0; i < siz; ++ i) {
int u = g[tmp][i];
if(vis[u]) continue;
vis[u] = 1;
dep[u] = dep[tmp] + 1;
que.push(u);
}
}
bool flag = 0;
int siz = q.size();
for(int i = 0; i < siz; ++ i) {
if(dep[q[i]] & 1) flag = 1;
}
if(flag) {
return 3;
}
return 1;
}
int main() {
cin >> n;
for(int i = 0, u, v; i < n - 1; ++ i) {
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
int x = solveMin();
int y = solveMax();
if(y == 2) y = 1;
cout << x << " " << y;
return 0;
}
ps 刚开始错了一个只有2个点的情况,这时候的最大值只有1,要特判一下,(要不是cf能直接看数据点也不知道会卡到什么时候((啊啊啊