BSOJ3392【省选模拟】树上的询问

题目

BSOJ3392【省选模拟】树上的询问

分析

点分治。

点分治入门题,首先这题可以直接做,也可以转化成 "小于等于 \(k\) 的减掉 小于等于 \(k-1\) 的" ,然后相减来做。

两者皆可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
inline int inc(int x,int v,int mod){x+=v;return x>=mod?x-mod:x;}
inline int dec(int x,int v,int mod){x-=v;return x<0?x+mod:x;}
inline int read(){int x=0,f=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
inline void write(int x){if(x==0){putchar(48);return;}int len=0,dg[20];while(x>0){dg[++len]=x%10;x/=10;}for(register int i=len;i>=1;i--)putchar(dg[i]+48);}
const int N=1e5+5;
const int M=1e7+5;
struct node{
    int to,next,val;
}edge[1000005];
int used[N],head[N],idy,q[N],maxson[N],tot,size[N],dis[N],rev[N],cnt;
bool vis[N],ans[N],rvis[M];
int n,m,id,idx;
void add(int u,int v,int w){
    edge[++idx].to=v;
    edge[idx].next=head[u];
    edge[idx].val=w;
    head[u]=idx;
    return ;
}
void dfs(int x,int fa){ 
	size[x]=1;
	maxson[x]=0;
	for(int i=head[x];i;i=edge[i].next){
		int y=edge[i].to;
		if(y==fa||vis[y])continue;
		dfs(y,x);
		size[x]+=size[y];
		maxson[x]=max(maxson[x],size[y]);
	}
	maxson[x]=max(maxson[x],tot-size[x]);
	if(maxson[x]<maxson[id])id=x;
	return ;
}
void dist(int x,int fa){
	rev[++cnt]=dis[x];
	for(int i=head[x];i;i=edge[i].next){
		int y=edge[i].to;
		if(y==fa||vis[y])continue;
		dis[y]=dis[x]+edge[i].val;
		dist(y,x);
	}
}
void calc(int x){
	idy=0;
	for(int i=head[x];i;i=edge[i].next){
		int y=edge[i].to;
		if(vis[y])continue;
		cnt=0;
		dis[y]=edge[i].val;
		dist(y,x);
		for(int j=1;j<=cnt;j++){
			for(int k=1;k<=m;k++){
				if(q[k]-rev[j]>=0&&q[k]-rev[j]<=1e7 && rvis[q[k]-rev[j]])ans[k]=1;
			}
		}
		for(int j=1;j<=cnt;j++) if(rev[j]<=1e7)used[++idy]=rev[j],rvis[rev[j]]=1;
	}
	for(int i=1;i<=idy;i++)rvis[used[i]]=0;
}
void solve(int x){
	vis[x]=rvis[0]=1;
	calc(x);
	for(int i=head[x];i;i=edge[i].next){
	    int y=edge[i].to;
		if(vis[y])continue;
		id=0;
		maxson[id]=tot=size[y];
		dfs(y,0);
		solve(id);
	}
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n-1;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z),add(y,x,z);
    }
	for(int i=1;i<=m;i++)q[i]=read();
    maxson[id]=tot=n;
    dfs(1,0);
    solve(id);
    for(int i=1;i<=m;i++){
    	printf("%s\n",(ans[i]||(!q[i])) ? "Yes" : "No");
	}
	return 0;
}

感受

这题第二种做法很巧妙,同样的办法在一道模拟题也见过,同样是容斥,但是那道题是 \(dp\)

posted @ 2021-05-07 11:43  __Anchor  阅读(31)  评论(0编辑  收藏  举报