点分治练习

点分治

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的路径对于答案的贡献是dis[0]dis[0]+2dis[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;
}

PKU-1741 Tree#

Tree

解题思路:#

点分治+二分,复杂度nlog2n

#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
*/
posted @   GrayKido  阅读(170)  评论(0编辑  收藏  举报
编辑推荐:
· 深入理解 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)
点击右上角即可分享
微信分享提示
主题色彩