zoukankan      html  css  js  c++  java
  • P3806树上点分治

    链接:https://www.luogu.org/problemnew/show/P3806

    我学习点分治的模板:https://www.cnblogs.com/Paul-Guderian/p/6782671.html

    题目描述

    给定一棵有n个点的树

    询问树上距离为k的点对是否存在。

    输入输出格式

    输入格式:

    n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径

    接下来m行每行询问一个K

    输出格式:

    对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)

    输入输出样例

    输入样例#1: 复制
    2 1
    1 2 2
    2
    输出样例#1: 复制
    AYE

    说明

    对于30%的数据n<=100

    对于60%的数据n<=1000,m<=50

    对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int M = 10005, K = 10000001;
    
    int n, tot, cnt, Ans, root, sum, h[M], siz[M], dis[M], tong[M], f[M], num[K+1];
    bool vis[M];
    struct edge{int v, nxt, w;}G[M<<1];
    void add(int u, int v, int w){
        G[++tot].v = v; G[tot].w = w; G[tot].nxt = h[u]; h[u] = tot;
    }
    void init(){
        memset(vis, 0, sizeof(vis));
        memset(h, 0, sizeof(h));
        tot = 0; Ans = 0; sum = 0;
    }
    
    
    void getdeep(int u, int fa){
        tong[++cnt] = dis[u];
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(vis[v] || v == fa)continue;
            dis[v] = dis[u] + G[i].w;    
            getdeep(v, u);    
        }
    }
    
    void getroot(int u, int fa){
        siz[u] = 1; f[u] = 0;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(vis[v] || v == fa)continue;
            getroot(v, u);
            siz[u] += siz[v];
            f[u] = max(f[u], siz[v]);
        }
        f[u] = max(f[u], sum - siz[u]);
        if(f[u] < f[root]) root = u; 
        
    }
    void cal(int u, int ret, bool opt){
        dis[u] = ret;
        cnt = 0; 
        getdeep(u, 0);
        int ans = 0;
        for(int i = 1; i <= cnt; i++)
            for(int j = i + 1; j <= cnt; j++){
                if(opt && tong[i] + tong[j] < K) ++num[tong[i] + tong[j]];
                else if(tong[i] + tong[j] < K) --num[tong[i] + tong[j]];    
            }
    }
    
    void solve (int u){
        cal(u, 0, 1);
        vis[u] = 1;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(vis[v])continue;
            cal(v, G[i].w, 0);
            sum = siz[v];
            getroot(v, root = 0);
            solve(root);
        }
    }
    
    
    int main(){
        f[0] = 1e9;
        int m, fg = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i < n; i++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w); add(v, u, w);
            if(!w)fg = 1;
        }
            
        solve(1);
        num[0] = fg;
        while(m--){
            int k; scanf("%d", &k);
            if(num[k])puts("AYE");
            else puts("NAY");
        }
    }
    View Code

    P4178 Tree

    链接:https://www.luogu.org/problemnew/show/P4178

    题目描述

    给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K

    输入输出格式

    输入格式:

    N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

    输出格式:

    一行,有多少对点之间的距离小于等于k

    输入输出样例

    输入样例#1: 复制
    7
    1 6 13 
    6 3 9 
    3 5 7 
    4 1 3 
    2 4 20 
    4 7 2 
    10
    输出样例#1: 复制
    5
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int M = 40005;
    
    int n, k, tot, cnt, Ans, root, sum, h[M], siz[M], dis[M], tong[M], f[M];
    bool vis[M];
    struct edge{int v, nxt, w;}G[M<<1];
    void add(int u, int v, int w){
        G[++tot].v = v; G[tot].w = w; G[tot].nxt = h[u]; h[u] = tot;
    }
    void init(){
        memset(vis, 0, sizeof(vis));
        memset(h, 0, sizeof(h));
        tot = 0; Ans = 0; sum = 0;
    }
    
    
    void getdeep(int u, int fa){
        tong[++cnt] = dis[u];
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(vis[v] || v == fa)continue;
            dis[v] = dis[u] + G[i].w;    
            getdeep(v, u);    
        }
    }
    
    void getroot(int u, int fa){
        siz[u] = 1; f[u] = 0;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(vis[v] || v == fa)continue;
            getroot(v, u);
            siz[u] += siz[v];
            f[u] = max(f[u], siz[v]);
        }
        f[u] = max(f[u], sum - siz[u]);
        if(f[u] < f[root]) root = u; 
        
    }
    
    int cal(int u, int ret){
        dis[u] = ret;
        cnt = 0; 
        getdeep(u, 0);
        int ans = 0;
        int lf = 1, rg = cnt;
        sort(tong+1, tong+1+cnt);
        while(lf < rg){
            if(tong[lf] + tong[rg] <= k) ans += rg - lf, lf++;
            else rg--;
        }
        return ans;
    }
    
    void solve (int u){
        Ans += cal(u, 0);
        vis[u] = 1;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(vis[v])continue;
            Ans -= cal(v, G[i].w);
            sum = siz[v];
            getroot(v, root = 0);
            solve(root);
        }
    }
    
    
    int main(){
        f[0] = 1e9;
        scanf("%d", &n);
        init();
        for(int i = 1; i < n; i++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w); add(v, u, w);
        }
        scanf("%d", &k);    
        solve(1);
        printf("%d
    ", Ans);
    }
    View Code
  • 相关阅读:
    BSGS
    聪聪可可(未完成)
    强连通分量,缩点
    bozj 1823(未完成)
    网络流
    bzoj1026
    点分治 poj1741
    bzoj 3270 博物馆
    高斯消元 模板
    bzoj 3143 [Hnoi2013]游走
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9395993.html
Copyright © 2011-2022 走看看