【BZOJ 1316】 树上的询问 树分治

原创 2017年01月03日 10:20:29

按理来说是一个非常简单的树分治,我只是为了将专题的时候作为一道引入题目的,不过,我擦set和map的常数差别有那么大吗,map居然比set慢了10倍,然后就一直T啊一直T最后看他们都用的set改过来就A了,我也是郁闷。

方法很简单,用set记录一个长度有没有出现过,然后每次树分治统计

    #include<cstdio>  
    #include<cstring>  
    #include<iostream>  
    #include<set>  
    #include<cstdlib>  
    #define maxn 30010  
    #define maxm 1000020  
    using namespace std;  
    int head[maxn],tot,dis[maxn],n,m,q[maxn],f[maxn],s[maxn],size,rt,vis[maxn],ans[maxn];  
    struct edge{int v,next,w;}e[maxn*2];  
    void adde(int a,int b,int c){e[tot].v=b,e[tot].w=c,e[tot].next=head[a];head[a]=tot++;}  
    set<int>Map;  
      
    void getrt(int u,int fa){  
        f[u]=0,s[u]=1;  
        for(int v,i=head[u];i!=-1;i=e[i].next){  
            if(vis[v=e[i].v]||v==fa)continue;  
            getrt(v,u);  
            s[u]+=s[v];  
            f[u]=max(f[u],s[v]);  
        }  
        f[u]=max(f[u],size-f[u]);  
        if(f[u]<f[rt])rt=u;  
    }  
      
    int cur[maxn*2],p;  
    void dfs(int u,int fa){  
        cur[++p]=dis[u];  
        for(int v,i=head[u];i!=-1;i=e[i].next){  
            if(vis[v=e[i].v]||v==fa)continue;  
            dis[v]=dis[u]+e[i].w;  
            dfs(v,u);  
        }  
    }  
       
    void calc(int u){  
        Map.clear();Map.insert(0);  
        for(int v,i=head[u];i!=-1;i=e[i].next){  
            if(vis[v=e[i].v])continue;  
            dis[v]=e[i].w,p=0;  
            dfs(v,u);  
            for(int j=1;j<=p;j++){  
                for(int k=1;k<=m;k++){  
                    if(Map.find(q[k]-cur[j])!=Map.end())ans[k]++;  
                }  
            }  
            for(int j=1;j<=p;j++)Map.insert(cur[j]);  
        }  
    }  
       
    void solve(int u){  
        vis[u]=1;  
        calc(u);  
        for(int i=head[u],v;i!=-1;i=e[i].next){  
            if(vis[v=e[i].v])continue;  
            f[rt=0]=size=s[v];  
            getrt(v,u);  
            solve(rt);  
        }  
    }  
       
    int main(){  
        memset(head,-1,sizeof(head));  
        scanf("%d%d",&n,&m);  
        for(int a,b,c,i=1;i<n;i++){  
            scanf("%d%d%d",&a,&b,&c);  
            adde(a,b,c),adde(b,a,c);  
        }  
        for(int i=1;i<=m;i++)scanf("%d",q+i);  
        f[rt=0]=size=n;  
        getrt(1,1);  
        solve(rt);  
        for(int i=1;i<=m;i++)if(ans[i]>0||q[i]==0)  
            puts("Yes");else puts("No");  
        return 0;  
    }  

版权声明:你喜欢就好

相关文章推荐

bzoj 3221: [Codechef FEB13] Obserbing the tree树上询问 (可持久化线段树+树链剖分)

题目描述传送门题目大意:给出一个n个节点的树 操作1:x,y a,k 将x到y路径上的点加入一个首项为a,公差为k等差数列 操作2:x,y 查询路径上的点权和 操作3:x回到第x次操作1后的结...

[bzoj 2152] 聪聪可可 树上点分治

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=21522152: 聪聪可可 Time Limit: 3 Sec Memory Limit: ...
  • ALPS233
  • ALPS233
  • 2016年05月13日 16:17
  • 3928

[BZOJ 3784][树上的路径][点分治+堆]

[BZOJ 3784][树上的路径][点分治+堆]题目大意:给定一个NN个结点的树,结点用正整数1…N1…N编号。每条边有一个正整数权值。用dist(a,b)dist(a,b)表示从结点aa到结点bb...
  • g1n0st
  • g1n0st
  • 2017年02月23日 14:02
  • 167

BZOJ 3784|树上的路径|点分治|堆|RMQ

求前M个路径,使路径权最小。和NOI 2010 超级钢琴类似。。。#include #include #include #define FOR(i,j,k) for(i=j;i...

bzoj 3784: 树上的路径 (ST表+优先队列+点分治)

题目描述传送门题目描述: 给定一个N个结点的树,结点用正整数1..N编号。每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路边上经过边的权值。其中要求a题解这道题用到了点分治的思想,但是重...

【BZOJ1912】【Apio2010】巡逻 树上最长链(才不是树的直径呢)

题解: 对于 k==0k==0 的情况: 我们发现遍历一棵树最后回到原点,那么对于所有的边,我们都是走过去,再走回来。 答案 (n−11)(n-1 对于 k==1k==1 的情况 设每条边长...
  • Vmurder
  • Vmurder
  • 2015年04月15日 17:47
  • 1913

【BZOJ 2588】Count on a tree 【树上路径第K大】【LCA+主席树】

其实不难..只是bug不好调QAQ #include #include #include #include #include #include #define g() getchar() #de...

bzoj3732 Network 最小生成树+LCA+树上倍增

这道题不就是Noip2013的t3吗…没想到bzoj换了个包装.noip2013货车运输是最大生成树,这里是最小生成树. 因为要是最大的边最小,则一定存在于最小生成树中.我们只需要跑一遍kruska...

BZOJ 3720 Gty的妹子树 树上分块

题目大意:给出一棵树,要求维护:1.求出以x为根节点的子树的严格大于y的数量。 2.将一个节点的权值改变。 3.在一个节点下加一个权值为y的节点。 思路:分块这个东西太神了(别找我分析时...

BZOJ 4034 树上操作 (树链剖分 线段树)

4034: [HAOI2015]树上操作Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...
  • w4149
  • w4149
  • 2017年07月05日 08:49
  • 108
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【BZOJ 1316】 树上的询问 树分治
举报原因:
原因补充:

(最多只允许输入30个字)