P3806 【模板】点分治1
解题思路:
点分治,我对于每次询问都直接计算...感觉复杂度挺大的..点分治处理出每个节点到根的距离,
排序后左右指针移动计算长度为k的路径数量
#include <bits/stdc++.h> using namespace std; /* freopen("k.in", "r", stdin); freopen("k.out", "w", stdout); */ // clock_t c1 = clock(); // std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl; //#pragma comment(linker, "/STACK:1024000000,1024000000") #define de(a) cout << #a << " = " << a << endl #define rep(i, a, n) for (int i = a; i <= n; i++) #define per(i, a, n) for (int i = n; i >= a; i--) typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> PII; typedef pair<double, double> PDD; typedef vector<int, int> VII; #define inf 0x3f3f3f3f const ll INF = 0x3f3f3f3f3f3f3f3f; const ll MAXN = 1e5 + 7; const ll MAXM = 1e6 + 7; const ll MOD = 1e9 + 7; const double eps = 1e-6; const double pi = acos(-1.0); struct Edge { int u, v, val, net; } e[MAXN << 1]; int cnt = -1; int head[MAXN]; int n, m, sum; int k; void add(int u, int v, int val) { e[++cnt].u = u; e[cnt].v = v; e[cnt].val = val; e[cnt].net = head[u]; head[u] = cnt; } int mx[MAXN], vis[MAXN], sz[MAXN]; int rt; int ans; void dfs(int now, int fa) { sz[now] = 1, mx[now] = 0; for (int i = head[now]; ~i; i = e[i].net) { int v = e[i].v; if (vis[v] || v == fa) continue; dfs(v, now); sz[now] += sz[v]; mx[now] = max(mx[now], sz[v]); } mx[now] = max(mx[now], sum - sz[now]); if (mx[now] < mx[rt]) rt = now; } int tot; int dis[MAXN]; void getdis(int now, int fa, int len) { for (int i = head[now]; ~i; i = e[i].net) { int v = e[i].v; if (vis[v] || v == fa) continue; dis[++tot] = len + e[i].val; getdis(v, now, dis[tot]); } } int solve(int now, int len) { int ret = 0; dis[tot = 1] = len; getdis(now, -1, len); int l = 1, r = tot; sort(dis + 1, dis + 1 + tot); while (l < r) { if (dis[l] + dis[r] == k) { l++, r--; ret++; } else if (dis[l] + dis[r] < k) l++; else r--; } // cout << ret << endl; return ret; } void divide(int now) { vis[now] = 1; ans += solve(now, 0); for (int i = head[now]; ~i; i = e[i].net) { int v = e[i].v; if (vis[v]) continue; ans -= solve(v, e[i].val); rt = 0; sum = sz[v]; dfs(v, now); divide(rt); } } void init() { memset(head, -1, sizeof(head)); cnt = -1; rt = 0; mx[0] = inf; } int main() { scanf("%d%d", &n, &m); init(); for (int i = 0; i < n - 1; i++) { int u, v, val; scanf("%d%d%d", &u, &v, &val); add(u, v, val); add(v, u, val); } for (int i = 0; i < m; i++) { scanf("%d", &k); memset(vis, 0, sizeof(vis)); ans = 0; rt = 0; sum = n; dfs(1, -1); divide(rt); printf("%s\n", ans ? "AYE" : "NAY"); } return 0; }
P2634 [国家集训队]聪聪可可
解题思路:
在上题代码上改solve函数就差不多了,模3后到根结点路径长度为0,1,2的路径对于答案的贡献是\(dis[0]*dis[0]+2*dis[1]*dis[2]\)
#include <bits/stdc++.h> using namespace std; /* freopen("k.in", "r", stdin); freopen("k.out", "w", stdout); */ // clock_t c1 = clock(); // std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl; //#pragma comment(linker, "/STACK:1024000000,1024000000") #define de(a) cout << #a << " = " << a << endl #define rep(i, a, n) for (int i = a; i <= n; i++) #define per(i, a, n) for (int i = n; i >= a; i--) typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> PII; typedef pair<double, double> PDD; typedef vector<int, int> VII; #define inf 0x3f3f3f3f const ll INF = 0x3f3f3f3f3f3f3f3f; const ll MAXN = 2e5 + 7; const ll MAXM = 1e6 + 7; const ll MOD = 1e9 + 7; const double eps = 1e-6; const double pi = acos(-1.0); struct Edge { int u, v, val, net; } e[MAXN << 1]; int cnt = -1; int head[MAXN]; int n; int sum; void add(int u, int v, int val) { e[++cnt].u = u; e[cnt].v = v; e[cnt].val = val; e[cnt].net = head[u]; head[u] = cnt; } int mx[MAXN], vis[MAXN], sz[MAXN]; int rt; ll ans; void dfs(int now, int fa) { sz[now] = 1, mx[now] = 0; for (int i = head[now]; ~i; i = e[i].net) { int v = e[i].v; if (vis[v] || v == fa) continue; dfs(v, now); sz[now] += sz[v]; mx[now] = max(mx[now], sz[v]); } mx[now] = max(mx[now], sum - sz[now]); if (mx[now] < mx[rt]) rt = now; } ll dis[4]; void getdis(int now, int fa, int len) { for (int i = head[now]; ~i; i = e[i].net) { int v = e[i].v; if (vis[v] || v == fa) continue; dis[(len + e[i].val) % 3]++; getdis(v, now, len + e[i].val); } } ll solve(int now, int len) { dis[0] = dis[1] = dis[2] = 0; dis[len % 3]++; getdis(now, -1, len); return dis[0] * dis[0] + 2 * dis[1] * dis[2]; } void divide(int now) { vis[now] = 1; ans += solve(now, 0); for (int i = head[now]; ~i; i = e[i].net) { int v = e[i].v; if (vis[v]) continue; ans -= solve(v, e[i].val); rt = 0; sum = sz[v]; dfs(v, now); divide(rt); } } void init() { memset(vis, 0, sizeof(vis)); memset(head, -1, sizeof(head)); cnt = -1; rt = 0; mx[0] = inf; } ll GCD(ll a, ll b) { return b == 0 ? a : GCD(b, a % b); } int main() { scanf("%d", &n); init(); for (int i = 0; i < n - 1; i++) { int u, v, val; scanf("%d%d%d", &u, &v, &val); val %= 3; add(u, v, val); add(v, u, val); } sum = n; dfs(1, -1); divide(rt); ll div = GCD(ans, 1LL * n * n); printf("%lld/%lld\n", ans / div, 1LL * n * n / div); // system("pause"); return 0; }