poj 1987 Distance Statistics 點分治

題目大意: 給你一棵樹,問兩個點對距離<=k的點對個數;


題目分析:點分治裸題。dfs處理出每個重心(分治下)到當前子樹根節點的距離存在dis數組中,o(n)直接找出。

但要注意的是,對於dis所存的距離,只適用於兩個不同的子樹當中,所以要將位於同一個子樹中的方案數減去。


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<cassert>
#include<climits>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define phiF (1000000006)
#define MAXN (1000000+10)
typedef long long LL;


struct info{
     int to,next,val;
     bool use;
}e[100005];
int x,y,z,n,m,tot,first[100005],son[50005],f[50005],size,root,a[50005],dis[50005],k,ans;

void add(int x,int y,int z){
	e[tot].to=y;
	e[tot].val=z;
	e[tot].next=first[x];
	first[x]=tot;tot++;
}


void findroot(int u,int fa){
	son[u]=1;f[u]=0;
	for (int p=first[u];p!=-1;p=e[p].next){
		int v=e[p].to;
		if (v==fa) continue;
		if (e[p].use) continue;
		findroot(v,u);
		f[u]=max(f[u],son[v]);	
		son[u]+=son[v];
	}
	f[u]=max(f[u],size-son[u]);
	if (f[u]<f[root]) root=u;
}

void dfs(int u,int fa){
	son[u]=1;
	a[++a[0]]=dis[u];
	for (int p=first[u];p!=-1;p=e[p].next){
		int v=e[p].to;
		if (!e[p].use&&v!=fa){
			dis[v]=dis[u]+e[p].val;
			dfs(v,u);
			son[u]+=son[v];
		}
	}
	
}


int  count(int u,int val){
	int tmp=a[0]=0;
	dis[u]=val;
	dfs(u,0);
	sort(a+1,a+a[0]+1);
	for (int l=1,r=a[0];l<r;){
		if (a[l]+a[r]<=k){
			tmp+=r-l;l++;
		} else r--;
	}
	return tmp;
	
}

void work(int u){
	ans+=count(u,0);
	for (int p=first[u];p!=-1;p=e[p].next){
		if (!e[p].use){
			e[p^1].use=true;
			ans-=count(e[p].to,e[p].val);
			f[0]=size=son[e[p].to];root=0;
			findroot(e[p].to,0);
			work(root);

		}
	}
	
	
}
char ch;

int main(){
	memset(first,-1,sizeof(first));
	scanf("%d%d",&n,&m);
	For (i,m){
		scanf("%d%d%d %c",&x,&y,&z,&ch);
		add(x,y,z);
		add(y,x,z);
	}
	scanf("%d",&k);
	f[0]=size=n;
	findroot(1,0);
	work(root);
	printf("%d",ans);
	
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章