点分治练习
点分治
P3806 【模板】点分治1#
解题思路:#
点分治,我对于每次询问都直接计算...感觉复杂度挺大的..点分治处理出每个节点到根的距离,一开始用桶算出点对数量,还是太慢TLE样例7和9,再看一波可以感觉出来这个点分治是不用套在询问里面的,可以离线对询问进行处理,只要一遍点分治就行了
T的代码#
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
using namespace __gnu_pbds;
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")
mt19937 rnd(time(NULL));
#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--)
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<char, char> PCC;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5 + 7;
const int MAXM = 4e5 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-7;
const double pi = acos(-1.0);
struct Edge
{
int u, v, len, net;
Edge(int _u = 0, int _v = 0, int _len = 0, int _net = 0) { u = _u, v = _v, len = _len, net = _net; }
} E[MAXN << 1];
int cnt = -1;
int head[MAXN];
int talu[MAXN * 100];
int sum;
int ans;
void add_edge(int u, int v, int w)
{
E[++cnt] = Edge(u, v, w, head[u]);
head[u] = cnt;
}
int rt; //重心
int mx[MAXN], sz[MAXN], vis[MAXN];
int dis[MAXN];
void init(int n)
{
rt = 0;
mx[0] = inf;
cnt = -1;
for (int i = 0; i <= n; i++)
head[i] = -1;
}
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;
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].len;
getdis(v, now, dis[tot]);
}
}
int n, m;
int k;
int solve(int now, int len)
{
int ret = 0;
dis[tot = 1] = len;
getdis(now, -1, len);
for (int i = 1; i <= tot; i++)
if (dis[i] <= k)
talu[dis[i]]++;
for (int i = 1; i <= tot; i++)
{
if (dis[i] <= k && talu[k - dis[i]])
{
if (2 * dis[i] == k)
ret += talu[k - dis[i]] - 1;
else
ret += talu[k - dis[i]];
}
}
for (int i = 1; i <= tot; i++)
if (dis[i] <= k)
talu[dis[i]] = 0;
return ret / 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].len);
rt = 0;
sum = sz[v];
dfs(v, now);
divide(rt);
}
return;
}
int main()
{
// freopen("k.in", "r", stdin);
// freopen("k.out", "w", stdout);
// clock_t c1 = clock();
scanf("%d%d", &n, &m);
init(n);
memset(talu, 0, sizeof(talu));
for (int i = 1; i <= n - 1; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
add_edge(v, u, w);
}
for (int i = 1; i <= m; i++)
{
scanf("%d", &k);
for (int j = 0; j <= n; j++)
vis[j] = 0;
ans = 0, rt = 0, sum = n;
dfs(1, -1);
divide(rt);
printf("%s\n", ans ? "AYE" : "NAY");
}
// std::cout << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
实际上通过的代码#
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
using namespace __gnu_pbds;
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")
mt19937 rnd(time(NULL));
#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--)
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<char, char> PCC;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5 + 7;
const int MAXM = 4e5 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-7;
const double pi = acos(-1.0);
struct Edge
{
int u, v, len, net;
Edge(int _u = 0, int _v = 0, int _len = 0, int _net = 0) { u = _u, v = _v, len = _len, net = _net; }
} E[MAXN << 1];
int cnt = -1;
int head[MAXN];
int talu[MAXN * 100];
int sum;
void add_edge(int u, int v, int w)
{
E[++cnt] = Edge(u, v, w, head[u]);
head[u] = cnt;
}
int rt; //重心
int mx[MAXN], sz[MAXN], vis[MAXN];
int dis[MAXN];
void init(int n)
{
rt = 0;
mx[0] = inf;
cnt = -1;
for (int i = 0; i <= n; i++)
head[i] = -1;
}
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;
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].len;
getdis(v, now, dis[tot]);
}
}
int n, m;
int k[MAXN];
int ans[MAXN];
vector<int> solve(int now, int len)
{
vector<int> vec;
dis[tot = 1] = len;
getdis(now, -1, len);
for (int j = 1; j <= m; j++)
{
int ret = 0;
for (int i = 1; i <= tot; i++)
if (dis[i] <= k[j])
talu[dis[i]]++;
for (int i = 1; i <= tot; i++)
{
if (dis[i] <= k[j] && talu[k[j] - dis[i]])
{
if (2 * dis[i] == k[j])
ret += talu[k[j] - dis[i]] - 1;
else
ret += talu[k[j] - dis[i]];
}
}
for (int i = 1; i <= tot; i++)
if (dis[i] <= k[j])
talu[dis[i]] = 0;
vec.emplace_back(ret / 2);
}
return vec;
}
void divide(int now)
{
vis[now] = 1;
vector<int> tmp = solve(now, 0);
for (int i = 1; i <= m; i++)
ans[i] += tmp[i - 1];
for (int i = head[now]; ~i; i = E[i].net)
{
int v = E[i].v;
if (vis[v])
continue;
tmp = solve(v, E[i].len);
for (int j = 1; j <= m; j++)
ans[j] -= tmp[j - 1];
rt = 0;
sum = sz[v];
dfs(v, now);
divide(rt);
}
return;
}
int main()
{
scanf("%d%d", &n, &m);
init(n);
memset(talu, 0, sizeof(talu));
for (int i = 1; i <= n - 1; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
add_edge(v, u, w);
}
for (int i = 1; i <= m; i++)
{
scanf("%d", &k[i]);
}
for (int j = 0; j <= n; j++)
vis[j] = 0;
for (int i = 0; i <= m; i++)
ans[i] = 0;
rt = 0, sum = n;
dfs(1, -1);
divide(rt);
for (int j = 1; j <= m; j++)
printf("%s\n", ans[j] ? "AYE" : "NAY");
return 0;
}
P2634 [国家集训队]聪聪可可#
解题思路:#
在上题代码上改solve函数就差不多了,模3后到根结点长度为0,1,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;
}
PKU-1741 Tree#
解题思路:#
点分治+二分,复杂度
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <set>
#include <vector>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <climits>
#include <queue>
#include <stack>
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;
Edge(int _u = 0, int _v = 0, int _val = 0, int _net = 0) { u = _u, v = _v, val = _val, net = _net; }
} e[MAXN << 1];
int cnt = -1;
int head[MAXN];
void add(int u, int v, int val)
{
e[++cnt] = Edge(u, v, val, head[u]);
head[u] = cnt;
}
int vis[MAXN], sz[MAXN], mx[MAXN];
int n, k, sum, rt;
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 ans;
int dis[MAXN];
//路径长度小于等于K点对数
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);
sort(dis + 1, dis + 1 + tot);
for (int i = 1; i <= tot; i++)
{
int temp = upper_bound(dis + 1, dis + 1 + tot, k - dis[i]) - dis - 1;
if (temp >= i)
temp--;
ret += temp;
}
return ret/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(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
cnt = -1;
rt = 0;
sum = n;
ans = 0;
mx[0] = inf;
}
int main()
{
while (~scanf("%d%d", &n, &k) && n + k)
{
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);
}
dfs(1, -1);
divide(rt);
printf("%d\n", ans);
}
return 0;
}
/*
5 4
1 2 3
1 3 1
1 4 2
3 5 1
5 4
1 2 1
2 3 2
3 4 3
4 5 2
*/
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)