淀粉质

主要思想就是每次找一个根使其任意一个子树大小小于\(\frac{size} 2\),处理跨根路径的答案然后删掉这个跟,并对于它的每一个子树继续分治


然后就没啦


luogu模板

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define M 400001
using namespace std;

int sum,q[M],x,y,z,rt,b[M],maxx=0x3f3f3f3f,n,m,k,d[M],ver[M],head[M],edge[M],nex[M],cnt,vis[M],s[M],c[M];
bool judge[10000001];
void add(int x,int y,int z)
{
    ver[++cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=z;
    ver[++cnt]=x; nex[cnt]=head[y]; head[y]=cnt; edge[cnt]=z;
}

void gr(int now,int fa)
{
    s[now]=1; int t=0;
    for(int i=head[now];i;i=nex[i])
    {
        if(ver[i]==fa || vis[i]) continue;
        gr(ver[i],now);
        s[now]+=s[ver[i]];
        t=max(t,s[ver[i]]);
    } 
    t=max(t,sum-s[now]);
    if(t<maxx) rt=now, maxx=t;
}

void gc(int now,int fa,int x)
{
    c[++c[0]]=x;
    for(int i=head[now];i;i=nex[i])
    {
        if(ver[i]==fa || vis[now]) continue;
        gc(ver[i],now,x+edge[i]);
    }
}

void calc(int now)
{
    c[0]=0;
    for(int i=head[now];i;i=nex[i])
    {
        if(vis[ver[i]]) continue;
        int u=c[0]+1; gc(ver[i],now,edge[i]);
        for(int j=u;j<=c[0];j++) 
            for(int l=1;l<=m;l++) if(q[l]>=c[j]) b[l]|=judge[q[l]-c[j]];
        for(int j=u;j<=c[0];j++) judge[c[j]]=1;
    }
    for(int i=1;i<=c[0];i++) judge[c[i]]=0;
}

void solve(int now)
{
    vis[now]=judge[0]=1; calc(now);
    for(int i=head[now];i;i=nex[i])
    {
        if(vis[ver[i]]) continue;
        sum=s[ver[i]]; maxx=0x3f3f3f3f; 
        gr(ver[i],now); solve(ver[i]);
    }
}

int main()
{
    scanf("%d%d",&n,&m); sum=n;
    for(int i=1;i<n;i++) 
        scanf("%d%d%d",&x,&y,&z), add(x,y,z);
    for(int i=1;i<=m;i++) scanf("%d",&q[i]);
    gr(1,0); solve(rt);
    for(int i=1;i<=m;i++) 
    if(b[i]) printf("AYE\n"); else printf("NAY\n"); 
} 

猜你喜欢

转载自www.cnblogs.com/ZUTTER/p/10345729.html
今日推荐