点分治

心情不好所以没改题,滚回去打点分治了
说下点分治的思路,首先要求找到树的重心,然后根据树的重心作为根,把树翻过来.
接着再在其子树中各个重复该过程,然后就能保证深度在log级别.
这个时候统计就能保证时间复杂度在深度上是正确的允许我们乱搞
然后是基础例题
正解放下面,就是点分治之后暴力.
这里有两种暴力方法,第二种比较巧,用两个指针跳去找某个值.
具体都写在里面了,(第一种注释了).

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define qr qr()
#define ps push_back
#define fi first
#define se second
#define pa pair<int,int>
#define ve vector
using namespace std;
const int N=2e5+200,INF=1e7;
int n,m;
inline ll qr{
	ll x=0;char ch=getchar();bool f=0;
	while(ch>57||ch<48)f=(ch=='-')?1:0,ch=getchar();
	while(ch>=48&&ch<=57)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
ve <pa> e[N];
int tot,vis[N],dis[N],mx[N],sz[N],bl[N];
int st[N],judge[INF],q[N],test[1500],query[1500];
int ans,sum,rt;
inline void add(int f,int t,int w){
	e[f].ps({t,w});
	e[t].ps({f,w});
}
void getrt(int u,int fa){
	sz[u]=1,mx[u]=0;//每一次进来重置sz,mx.
	for(auto i:e[u]){
		int v=i.fi;
		if(vis[v]||fa==v)continue;
		getrt(v,u);
		mx[u]=max(mx[u],sz[v]);
		sz[u]+=sz[v];
	}
	mx[u]=max(mx[u],sum-sz[u]);
	if(mx[rt]>mx[u])rt=u;
}
// void getdis(int u,int fa){
// 	st[++st[0]]=dis[u];
// 	for(auto i:e[u]){
// 		int v=i.fi;
// 		if(vis[v]||fa==v)continue;
// 		dis[v]=dis[u]+i.se;
// 		if(dis[v]>1e7)return;//总权值到达1e8级别,但查询只有1e7,减掉剩下部分.
// 		getdis(v,u);
// 	}
// }
void getdis(int u,int fa,int l){
	bl[u]=l;
	st[++tot]=u;
	for(auto i:e[u]){
		int v=i.fi;
		if(vis[v]||fa==v)continue;
		dis[v]=dis[u]+i.se;
		getdis(v,u,l);
	}
}
// void calc(int u){
// 	int p=0;
// 	for(auto i:e[u]){
// 		int v=i.fi;
// 		if(vis[v])continue;
// 		st[0]=0;dis[v]=i.se;//每次处理重置st,dis.
// 		getdis(v,u);
// 		for(int k=st[0];k;--k)//开栈拼凑
// 			for(int j=1;j<=m;++j)
// 				if(query[j]>=st[k])
// 					test[j]|=judge[query[j]-st[k]];
// 		for(int k=st[0];k;--k)
// 			q[++p]=st[k],judge[st[k]]=1;
// 	}
// 	for(int i=1;i<=p;++i)
// 		judge[q[i]]=0;
// }
bool cmp(int a,int b){
	return dis[a]<dis[b];
}
void calc(int u){
	tot=1;st[tot]=u;
	dis[u]=0;
	bl[u]=u;//这个赋值非常关键.
	for(auto i:e[u]){
		int v=i.fi;
		if(vis[v])continue;
		dis[v]=i.se;
		getdis(v,u,v);
	}
	sort(st+1,st+tot+1,cmp);
	for(int k=1;k<=m;++k){
		if(test[k])continue;
		int l=1,r=tot;
		while(l<r){
			if(dis[st[l]]+dis[st[r]]>query[k])--r;
			else if(dis[st[l]]+dis[st[r]]<query[k])++l;
			else if(bl[st[l]]==bl[st[r]]){
				if(dis[st[r-1]]==dis[st[r]])--r;
				else ++l;
			}else {test[k]=1;break;}
		}
	}
}
void solve(int u){
	vis[u]=1,calc(u);
	for(auto i:e[u]){
		int v=i.fi;
		if(vis[v])continue;
		sum=sz[v];mx[rt=0]=INF;
		getrt(v,0);solve(rt);
	}
}
void init(){
	n=qr;m=qr;
	for(int i=1;i<n;++i){
		int u=qr,v=qr,w=qr;
		add(u,v,w);
	}
	for(int i=1;i<=m;++i){
		query[i]=qr;
		if(!query[i])test[i]=1;
	}
	mx[rt]=sum=n;
	getrt(1,0);
	solve(rt);
	for(int i=1;i<=m;++i){
		if(test[i])printf("AYE\n");
		else printf("NAY\n");
	}
}
int main(){
	




	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);





	// ios::sync_with_stdio(0);
	// cin.tie(0);
	// cout.tie(0);
	init();
	return 0;
}

点分树就先搁置吧.

posted @ 2024-07-26 19:33  SLS-wwppcc  阅读(10)  评论(0)    收藏  举报