P3806 【模板】点分治1

  

题目背景

感谢hzwer的点分治互测。

题目描述

给定一棵有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

除了work函数需要重写 其他的都比较模板
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=1e5+10;
int n,m,ans[N],a[N],num,root,SIZE,siz[N],pos,head[N],maxx,f[N],vis[N];
struct Edge{int to,nex,w;}edge[N];
void add(int a,int b,int c)
{
    edge[++pos]=(Edge){b,head[a],c};
    head[a]=pos;
}
void getroot(int x,int fa)
{
    f[x]=0;siz[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;if(vis[v]||v==fa)continue;
        getroot(v,x);
        f[x]=max(f[x],siz[v]);
        siz[x]+=siz[v];
    }
    f[x]=max(f[x],SIZE-siz[x]);
    if(f[x]<f[root])root=x;
}
struct node
{
    int id,v;
}dis[N];
void dfs(int x,int fa,int id,int d)
{
    dis[++num]=(node){id,d};
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v]||v==fa)continue;
        dfs(v,x,id,d+edge[i].w);
    }
}
int find1(int x)
{
    int ans=0,L=1,R=num;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(dis[mid].v>=x)ans=mid,R=mid-1;
        else L=mid+1;
    }
    return ans;
}
void work(int x)
{
    num=0;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        dfs(v,x,v,edge[i].w);
    }
    dis[++num]=(node){0,0};
    sort(dis+1,dis+1+num,[](node a,node b){return a.v<b.v;});
    rep(i,1,m)
    {
        if(ans[i])continue;
        int L=1;
        while(L<num&&dis[L].v+dis[num].v<a[i])L++;
        while(L<num&&!ans[i])
        {
            if(2*dis[L].v>a[i])break;
            int pos=find1(a[i]-dis[L].v);
            while(L<=num&&dis[pos].id==dis[L].id&&dis[pos].v+dis[L].v==a[i])pos++;
            if(dis[pos].v+dis[L].v==a[i])ans[i]=1;
            L++;
        }
    }
}
void solve(int x)
{
    vis[x]=1;
    work(x);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        root=0;
        siz[root]=SIZE=siz[v];
        getroot(v,0);
        solve(v);
    }
}
int main()
{
    cin>>n>>m;
    rep(i,1,n-1)
    {
        int a,b,c;cin>>a>>b>>c;
        add(a,b,c);add(b,a,c);
    }
    rep(i,1,m)cin>>a[i];

    f[root]=SIZE=n;
    getroot(1,0);
    solve(root);
    rep(i,1,m)
    if(ans[i])printf("AYE
");
    else printf("NAY
");
    return 0;
}
View Code

容斥写法
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int N=2e5+6;
ll mod=1e9+7;
int n,m,cnt,dis[N],head[N],pos,siz[N],siz_tree,x,y,z,vis[N],root,maxson[N],ans[10000001];
struct Edge{int to,nex,v;}edge[N<<1];
void add(int a,int b,int c){edge[++pos]=(Edge){b,head[a],c};head[a]=pos;}

void getroot(int x,int fa)
{
    siz[x]=1;maxson[x]=0;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v]||v==fa)continue;
        getroot(v,x);siz[x]+=siz[v];
        maxson[x]=max(maxson[x],siz[v]);
    }
    maxson[x]=max(maxson[x],siz_tree-siz[x]);
    if(maxson[x]<maxson[root])root=x;
}

void getdis(int x,int fa,int nowdis)
{
    dis[++dis[0]]=nowdis;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==fa||vis[v])continue;
        getdis(v,x,nowdis+edge[i].v);
    }
}

void calc(int x,int d,int flag)
{
    dis[0]=0;
    getdis(x,0,d);
    for(int i=1;i<=dis[0];i++)
    for(int j=1;j<=dis[0];j++)if(i!=j&&dis[i]+dis[j]<=10000000)
    ans[dis[i]+dis[j]]+=flag;
}
void solve(int x)
{
    calc(x,0,1);
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        calc(v,edge[i].v,-1);
        root=0;
        siz_tree=siz[v];
        getroot(v,x);
        solve(root);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
    siz_tree=maxson[0]=n;
    root=0;
    getroot(1,0);
    solve(root);
    for(int i=1;i<=m;i++)scanf("%d",&x),printf("%s
",ans[x]>0?"AYE":"NAY");
}
View Code






原文地址:https://www.cnblogs.com/bxd123/p/11372598.html