版权声明:_ https://blog.csdn.net/lunch__/article/details/81982960
今天题目又爆零啊, 遇到这种毒瘤题我这种菜鸡 注定退役了
T1
这个题目很容易发现链的答案就是
假如不是链的话,那么至少存在一个度数大于 的点
如果我们把这个点作为根,那么每个点断开后通往其祖先的联通块内一定存在一个黑点,这样子我们对于每个点只用考虑它的子树了,记 为 子树内的黑点数,那么 ,如果有 个子树内还没有点的话,那么对 个子树内放点就好了,因为向祖先的那个联通块一定是联通的…
这种辣鸡 都没想出来我是真的菜
Codes
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
vector<int> G[N];
int f[N], de[N];
int n, root, ans;
void dfs(int u, int fa) {
int sum = 0;
for(auto v : G[u])
if(v != fa) {
dfs(v, u);
f[u] += f[v];
if(!f[v]) ++ sum;
}
if(sum) f[u] += sum - 1;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("bf.in", "r", stdin);
freopen("bf.out", "w", stdout);
#endif
int x, y;
scanf("%d", &n);
for(int i = 1; i < n; ++ i) {
scanf("%d%d", &x, &y);
G[x].pb(y), G[y].pb(x);
++ de[x], ++ de[y];
if(de[x] > de[root]) root = x;
if(de[y] > de[root]) root = y;
}
if(de[root] <= 2) return printf("1"), 0;
dfs(root, -1);
printf("%d\n", f[root]);
return 0;
}
T2
T3
这道题好像数据不是很强…?,我三个 的做法都不是最慢的
如果一条路径完全覆盖另一条,那么另一条的两个端点一定都在这条路径上
对这棵树做下树链剖分,然后重链的 序就是连续的了,对于每一条路径 ,把对于一个端点开一个 把另一个端点放在上面。
主席树上维护的是每个 序的出现的次数
每次在其父亲的基础上开新的版本
但是查询我不知道怎么
搞,于是我把重链都存下来了..
每次
枚举两条重链 再用主席树查询就好了..
时间复杂度
Codes
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
int read() {
int _ = 0, ___ = 1; char __ = getchar();
for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
return _ * ___;
}
const int N = 2e5 + 10;
vector<int> G[N], D[N];
int n, m, root[N];
int X[N], Y[N];
struct Chairman_Tree {
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
int cnt;
struct node {
int ch[2], sum;
}T[N * 70];
void update(int &x, int pre, int l, int r, int p) {
T[x = ++ cnt] = T[pre]; ++ T[x].sum;
if(l != r) {
if(p <= mid) update(ls(x), ls(pre), l, mid, p);
else update(rs(x), rs(pre), mid + 1, r, p);
}
}
int query(int x, int pre, int l, int r, int L, int R) {
int res = 0;
if(L <= l && r <= R)
res = T[x].sum - T[pre].sum;
else {
if(L <= mid) res += query(ls(x), ls(pre), l, mid, L, R);
if(R > mid) res += query(rs(x), rs(pre), mid + 1, r, L, R);
}
return res;
}
}T;
void add(int x, int y) {
G[x].pb(y), G[y].pb(x);
}
int dep[N], fa[N], id[N], size[N];
int heavy[N], top[N], cnt;
int sumx[N], sumy[N];
void dfs1(int x) {
size[x] = 1;
for(auto v : G[x])
if(!dep[v]) {
dep[v] = dep[x] + 1;
fa[v] = x;
dfs1(v);
size[x] += size[v];
if(size[v] > size[heavy[x]])
heavy[x] = v;
}
}
void dfs2(int x, int ancestor) {
id[x] = ++ cnt; top[x] = ancestor;
if(heavy[x]) dfs2(heavy[x], ancestor);
for(auto v : G[x])
if(v != fa[x] && v != heavy[x])
dfs2(v, v);
}
void dfs3(int x) {
root[x] = root[fa[x]];
for(auto v : D[x])
T.update(root[x], root[x], 1, n, id[v]);
for(auto v : G[x])
if(v != fa[x])
dfs3(v);
}
void Init() {
read(), n = read(), m = read();
for(int i = 1; i < n; ++ i)
add(read(), read());
for(int i = 1; i <= m; ++ i) {
X[i] = read(), Y[i] = read();
D[X[i]].pb(Y[i]);
}
dfs1(dep[1] = 1); dfs2(1, 1); dfs3(1);
}
int cal(int x, int y) {
ll res = 0; sumx[0] = sumy[0] = 0;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]])
swap(x, y);
sumx[++ sumx[0]] = top[x];
sumy[++ sumy[0]] = x;
x = fa[top[x]];
}
if(dep[x] > dep[y])
swap(x, y);
sumx[++ sumx[0]] = x;
sumy[++ sumy[0]] = y;
for(int i = 1; i <= sumx[0]; ++ i)
for(int j = 1; j <= sumy[0]; ++ j)
res += T.query(root[sumy[i]], root[fa[sumx[i]]], 1, n, id[sumx[j]], id[sumy[j]]);
return res;
}
void Solve() {
int res = 0;
for(int i = 1; i <= m; ++ i)
res += cal(X[i], Y[i]);
ll x = res - m, y = 1ll * m * (m - 1) / 2;
// cout << x << ' ' << y << endl;
ll gcd = __gcd(x, y);
printf("%lld/%lld", x / gcd, y / gcd);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("std.in", "r", stdin);
freopen("std.out", "w", stdout);
#endif
Init();
Solve();
return 0;
}