• BZOJ1316: 树上的询问


    【传送门:BZOJ1316


    简要题意:

      给出一棵n个点的带边权有根树

      有q个询问,每个询问输入len,判断在树上是否存在长度为len的路径


    题解:

      直接点分治,用set保存链的长度就行了


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #define Maxn 11000
    #define INF 1<<30
    using namespace std;
    struct node{int x,y,d,next;}a[Maxn*2];int len,last[Maxn];
    void ins(int x,int y,int c){a[++len]=(node){x,y,c,last[x]};last[x]=len;}
    int ms[Maxn],sum,tot[Maxn],rt;
    bool v[Maxn];
    set<int> S;
    void getrt(int x,int fa)
    {
        tot[x]=1;ms[x]=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y==fa||v[y]==true) continue;
            getrt(y,x);
            tot[x]+=tot[y];
            ms[x]=max(ms[x],tot[y]);
        }
        ms[x]=max(ms[x],sum-tot[x]);
        if(ms[x]<ms[rt]) rt=x;
    }
    int dep[Maxn],Q,q[Maxn];
    int p[Maxn];
    void cal(int x,int fa,int d)
    {
        for(int i=1;i<=Q;i++) if(S.find(q[i]-d)!=S.end()) p[i]=true;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y==fa||v[y]==true) continue;
            cal(y,x,d+a[k].d);
        }
    }
    void add(int x,int fa,int d)
    {
        S.insert(d);
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y==fa||v[y]==true) continue;
            add(y,x,d+a[k].d);
        }
    }
    void solve(int x)
    {
        v[x]=true;S.insert(0);
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(v[y]==true) continue;
            cal(y,x,a[k].d);
            add(y,x,a[k].d);
        }
        S.clear();
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(v[y]==true) continue;
            rt=0;sum=tot[y];getrt(y,x);
            solve(rt);
        }
    }
    int main()
    {
        int n;
        scanf("%d%d",&n,&Q);
        len=0;memset(last,0,sizeof(last));
        for(int i=1;i<n;i++)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            ins(x,y,c);ins(y,x,c);
        }
        memset(v,false,sizeof(v));
        rt=0;sum=ms[rt]=n;getrt(1,0);
        memset(p,false,sizeof(p));
        for(int i=1;i<=Q;i++) scanf("%d",&q[i]);
        solve(rt);
        for(int i=1;i<=Q;i++)
        {
            if(p[i]==true||q[i]==0) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }

     

  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/Never-mind/p/10154042.html
Copyright © 2020-2023  润新知