• 点分治


    /*
    点分治:
    我们先随意指定一个根rt,将这棵树转化成有根树
    不难发现树上的路径分为两类, 经过根节点rt的路径和包含于rt的某棵子树里(不经过rt)的路径
    
    对于前者, 我们用dis[u]表示结点u到根节点rt的路径长度, 
    则u到v的路径长即为dis[u]+dis[v]
    
    对于后者, 既然u到v的路径包含在rt的某个子树内, 那么我们就找到这棵子树的根,再对他求一次第一类路径
    这样分治的思想就很明显了
    
    就是把原来的树分成很多小的子树,并对每个子树分别求解第一类路径
    点分治过程中,每一层的所有递归过程合计对每个点处理一次 假设共递归T层,则总时间复杂度为O(T*N)
    然而,如果树退化成一条链 那么递归层数就是T=n,总时间复杂度为O(N^2)
    这样显然不能承受,所以我们要让树的层数经量少 这里就要找树的重心
    
    注意:因为边的权值总和会达到1e8,而查询用到的桶的范围只到1e7,所以如果求出来的路径超过了1e7,则不用记录下来
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=5e4+10;
    typedef long long ll;
    int n,m;
    int head[maxn],cnt=0;
    struct edge{
        int v,next;
        int w;
    }e[maxn<<1];
    int root,sum;
    int size[maxn],dp[maxn],tot=0,dis[maxn];
    bool vis[maxn],judge[10000010];
    void add(int u,int v,int w){
        e[cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt++;
    }
    int query[maxn],rem[maxn];
    bool is_ok[maxn];//第i个询问是否合法
    int temp[maxn];
    int minNodeSize;
    
    void getroot(int u,int f){
        size[u]=1;dp[u]=0;
        for (int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(v==f || vis[v]) continue;
            getroot(v,u);
            size[u]+=size[v];
            dp[u]=max(dp[u],size[v]);
        }
        dp[u]=max(dp[u],sum-size[u]);
        if(dp[u]<dp[root]) root=u;
    }
    void getdis(int u,int f){
        rem[++tot]=dis[u];
        for (int i=head[u];~i;i=e[i].next){
            int v=e[i].v,w=e[i].w;
            if(v==f || vis[v]) continue;;
            if(dis[u]+w<=1e7) dis[v]=dis[u]+w;
            getdis(v,u);
        }
    }
    void cal(int u){
        int p=0;
        for (int i=head[u];~i;i=e[i].next){
            int v=e[i].v,w=e[i].w;
            if(vis[v]) continue;
            tot=0,dis[v]=w;getdis(v,u);
            for (int j=1;j<=tot;j++){
                for (int k=1;k<=m;k++){
                    if(rem[j]<=query[k]) is_ok[k]|=judge[query[k]-rem[j]];
                }
            }
    
            //更新judge
            for (int j=1;j<=tot;j++){
                temp[++p]=rem[j];judge[rem[j]]=true;
            }
        }
        //处理完这颗子树清空judge
        for (int i=1;i<=p;i++){
            judge[temp[i]]=0;
        }
    }
    void solve(int u){ 
        vis[u]=judge[0]=1;
        cal(u);
        for (int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(vis[v]) continue;
            sum=size[v];
            dp[root=0]=n;
            getroot(v,u);
            solve(root);
        }
    }
    
    int main(){
        memset(head,-1,sizeof(head));cnt=0;
    
        cin>>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);
        }
        for (int i=1;i<=m;i++){
            scanf("%d",&query[i]);
        }
        sum=root=n;
        getroot(1,0);
        solve(root);
        for (int i=1;i<=m;i++){
            printf(is_ok[i]==1?"AYE
    ":"NAY
    ");
        }
        return 0;
    }
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    scrapy的自动限速(AutoThrottle)扩展
    js可以控制文件上传的速度吗?
    用DataReader 分页与几种传统的分页方法的比较
    jdbc分页查询
    几种分页方式分析.
    mybatis下的分页,支持所有的数据库
    java 物理分页和逻辑分页
    IBatis的分页研究
    JDBC分页
    用Java实现异构数据库的高效通用分页查询功能
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13818737.html
Copyright © 2020-2023  润新知