点分治60pts求条

P3806 【模板】点分治 1

5t0_0r2 @ 2024-04-19 13:51:53

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 9,M = 109,K = 1e7 + 9;
int n,m;
struct edge{
    int to,cost,nex;
} e[N << 1];
int head[N],ecnt;
void addedge(int u,int v,int w){
    ecnt++;
    e[ecnt] = (edge){v,w,head[u]};
    head[u] = ecnt;
}
int dp[N],siz[N],dis[N];
int rec[N],rec_top;//记录出现过的距离
int tmp[K],tmp_top;
bool vis[N];
int query[M];
bool exist[K],ans[M];
int tot,Center;
void get_center(int u,int fa){//寻找重心 
    dp[u] = 0;siz[u] = 1;
    for(int i = head[u];i;i = e[i].nex){
        int v = e[i].to,w = e[i].cost;
        if(vis[v] || v == fa)
            continue;
        get_center(v,u);
        siz[u] += siz[v];
        dp[u] = max(dp[u],siz[v]);
    }
    if(max(dp[u],tot - siz[u]) < dp[Center])
        Center = u;
}
void get_dis(int u,int fa){//获得子树所有节点及到根的距离 
    rec[++rec_top] = dis[u];
    for(int i = head[u];i;i = e[i].nex){
        int v = e[i].to,w = e[i].cost;
        if(vis[v] || v == fa)
            continue;
        dis[v] = dis[u] + w;
        get_dis(v,u);
    }
}
void merge(int u){//合并答案 
    tmp_top = 0;
    for(int i = head[u];i;i = e[i].nex){
        int v = e[i].to,w = e[i].cost;
        if(vis[v])
            continue;
        rec_top = 0;dis[v] = w;
        get_dis(v,u);
        for(int j = 1;j <= rec_top;j++)
            for(int k = 1;k <= m;k++)
                if(query[k] >= rec[j])
                    ans[k] |= exist[query[k] - rec[j]];
        for(int j = 1;j <= rec_top;j++){
            tmp[++tmp_top] = rec[j];
            exist[rec[j]] = true;
        }
    }
    for(int i = 1;i <= tmp_top;i++)
        exist[tmp[i]] = false;
}
void solve(int u){//点分治主体 
    vis[u] = true;
    merge(u);
    for(int i = head[u];i;i = e[i].nex){
        int v = e[i].to,w = e[i].cost;
        if(vis[v])
            continue;
        dp[0] = n;Center = 0;tot = siz[v];
        get_center(v,u);
        solve(Center);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin >> n >> m;
    for(int i = 1;i < n;i++){
        int u,v,w;
        cin >> u >> v >> w;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    for(int i = 1;i <= m;i++)
        cin >> query[i];
    dp[0] = tot = n;
    get_center(1,0);
    exist[0] = true;
    solve(Center);
    for(int i = 1;i <= m;i++)
        cout << (ans[i] ? "AYE" : "NAY") << '\n';
    return 0;
}

by __Chx__ @ 2024-04-19 15:35:30

@5t0_0r2

应将:

if(max(dp[u],tot - siz[u]) < dp[Center]) 
    Center = u;

改为:

dp[u]=max(dp[u],tot - siz[u]);
if(dp[u] < dp[Center]) 
    Center = u;

因为如果不更新 dp[u] 的值,后面所判断的 <dp[Center] 并不是 u 的最大子树。

建议在 get_dis 时同时更新 siz 的值,详细可以见这个。


by 5t0_0r2 @ 2024-04-19 21:00:12

@Chx thx


|