1. 程式人生 > 實用技巧 >Windows XP 組策略的應用 一

Windows XP 組策略的應用 一

點分治可以解決樹上大規模路徑問題

過程 :

每次找出重心,處理出所有跨過重心的資訊,例如將一條長\(k\)的路徑拆成兩條跨過重心的鏈,然後遞迴處理,只會遞迴\(O(log_n)\)層,總複雜度為\(O(nlog_n)\)

  • \(trick\) : 將每層處理的節點放入佇列裡,然後彈出佇列清空,直接\(memset\)複雜度不對

例題:

  • Luogu 3806

沒什麼好說的,板子題,按照上面說的直接做就好了

程式碼 :

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
	const int maxn = 1e4+5;
	const int maxm = 1e7+5;
	const int inf = 1e9+7;
	int head[maxn],que[maxn],dis[maxn],siz[maxn],maxx[maxn],d[maxn];
	int n,ecnt,m,sum,rt,cnt;
	bool vis[maxn],ins[maxm],ans[maxn];
	queue<int> tag;
	struct edge
	{
		int to,nxt,val;
	}e[maxn<<1];
	
	void add(int u,int v,int w)
	{
		e[++ecnt].to=v;
		e[ecnt].val=w;
		e[ecnt].nxt=head[u];
		head[u]=ecnt;
	}
	
	void calcsiz(int u,int fa)
	{
		siz[u]=1;
		maxx[u]=0;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(v==fa||vis[v]) continue;
			calcsiz(v,u);
			siz[u]+=siz[v];
			maxx[u]=max(maxx[u],siz[v]);
		}
		maxx[u]=max(maxx[u],sum-siz[u]);
		if(maxx[u]<maxx[rt]) rt=u;
	}
	
	void calcdis(int u,int fa)
	{
		d[++cnt]=dis[u];
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(v==fa||vis[v]) continue;
			dis[v]=dis[u]+e[i].val;
			calcdis(v,u);
		}
	}
	
	void dfz(int u,int fa)
	{
		ins[0]=true;
		tag.push(0);
		vis[u]=true;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(v==fa||vis[v]) continue;
			dis[v]=e[i].val;
			calcdis(v,u);
			for(int j=1;j<=cnt;j++)
			{
				for(int k=1;k<=m;k++)
				{
					if(que[k]>=d[j]) ans[k]|=ins[que[k]-d[j]];
				}
			}
			for(int j=1;j<=cnt;j++)
			{
				if(d[j]<=10000000) ins[d[j]]=true,tag.push(d[j]);
			}
			cnt=0;
		}
		while(!tag.empty()) ins[tag.front()]=false,tag.pop();
		for(int i=head[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(v==fa||vis[v]) continue;
			sum=siz[v];
			rt=0;
			maxx[rt]=inf;
			calcsiz(v,u);
			calcsiz(rt,-1);
			dfz(rt,u);	
		} 
	}
	
	void work()
	{
		int a,b,c;
		scanf("%d%d",&n,&m);
		for(int i=1;i<n;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			add(a,b,c);add(b,a,c);
		}
		for(int i=1;i<=m;i++) scanf("%d",&que[i]);
		rt=0;
		sum=n;
		maxx[rt]=inf;
		calcsiz(1,-1);
		calcsiz(rt,-1);
		dfz(rt,-1);
		for(int i=1;i<=m;i++)
		{
			if(ans[i]) printf("AYE\n");
			else printf("NAY\n");
		}
	}

}

int main()
{
	zzc::work();
	return 0;
}