[POJ1741]Tree

The meaning of the title: For a tree with edge weights, count the number of point pairs with a distance $\leq k$

This basic thing has been pigeon for so long, I should retire it...

Divide and conquer is used to count point pairs or paths that satisfy certain properties, but it is actually a big violence

This problem requires counting the number of point pairs with distance $\leq k$ on the tree, then we do this:

For the current node $x$, traverse the subtree and calculate the distance $dis_u$ from all descendants of $x$ to $x$, sort them and use double pointers to count the logarithm of $dis_i+dis_j\leq k$, record this The operation is $\text{calc}(x)$

Obviously this will count pairs of points in the same subtree from $x$ whose on-tree paths do not go through $x$, so we also need to subtract the answer for all the sons $u$ of $x$ Go to $\text{calc}(u)$, so that we have successfully counted all the point pairs that satisfy the condition of $x$

But we also need to count the number of point pairs that do not pass through $x$, then recursively do the above operation directly to each son of $x$

It is easy to find that the amount of calculation each time is $siz_x$, and we want to minimize this sum, so each time we first find the center of gravity, and then use the center of gravity as the root for subsequent operations.

So the whole process is probably like this: let $\text{solve}(x)$ represent the answer in the subtree rooted at $x$

Find the center of gravity $c$ in the subtree of $x$, the answer $+=\text{calc}(c)$, set $c$ to be inaccessible in subsequent recursion, for each son of $c$ $u $, answer $-=\text{calc}(u)$, recursively call $\text{solve}(u)$, then it's gone

There is another way of writing the answer of point divide and conquer statistics. This way of writing does not require deduplication, but counts the contributions generated between the two sets.

The same is to find the center of gravity $c$, the initial time $S=\varnothing$, for each son $u$ of $c$, count the contribution of points in the $u$ subtree and points in $S$ (to For each point in the $u$ subtree, find how many points in $S$ can form a matching point pair with it), then let $S\gets S\cup\{u\}$, the other parts are the same as The first method is exactly the same. This writing method usually requires data structure to assist the query, and each has its own advantages and disadvantages.

Finally filled a hole? (fog

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int inf=2147483647;
int h[10010],nex[20010],to[20010],w[20010],t[10010],siz[10010],M,k,ans;
bool v[10010];
void add(int a,int b,int c){
	M++;
	to[M]=b;
	w[M]=c;
	nex[M]=h[a];
	h[a]=M;
}
int n,mn,cn;
void dfs1(int fa,int x){
	n++;
	you [x] = 1;
	for(int i=h[x];i;i=nex[i]){
		if(!v[to[i]]&&to[i]!=fa){
			dfs1(x,to[i]);
			you [x] + = you [to [i]];
		}
	}
}
void dfs2(int fa,int x){
	int i,k;
	k=0;
	for(i=h[x];i;i=nex[i]){
		if(!v[to[i]]&&to[i]!=fa){
			dfs2(x,to[i]);
			k=max(k,siz[to[i]]);
		}
	}
	k = max (k, n-siz [x]);
	if(k<mn){
		mn = k;
		cn=x;
	}
}
void dfs3(int fa,int x,int d){
	t[++M]=d;
	for(int i=h[x];i;i=nex[i]){
		if(!v[to[i]]&&to[i]!=fa)dfs3(x,to[i],d+w[i]);
	}
}
int calc(int x,int dt){
	M=0;
	dfs3(0,x,dt);
	sort(t+1,t+M+1);
	int l=1,r=M,res=0;
	while(l<r){
		if(t[l]+t[r]<=k){
			res+=r-l;
			l++;
		}else
			r--;
	}
	return res;
}
void solve(int x){
	int i;
	n=0;
	dfs1(0,x);
	mn=inf;
	dfs2(0,x);
	x=cn;
	ans+=calc(x,0);
	v[x]=1;
	for(i=h[x];i;i=nex[i]){
		if(!v[to[i]]){
			ans-=calc(to[i],w[i]);
			solve(to[i]);
		}
	}
}
int main(){
	int n,i,a,b,c;
	scanf("%d%d",&n,&k);
	while(n|k){
		M=0;
		memset(h,0,sizeof(h));
		memset(v,0,sizeof(v));
		for(i=1;i<n;i++){
			scanf("%d%d%d",&a,&b,&c);
			add(a,b,c);
			add(b,a,c);
		}
		years=0;
		solve(1);
		printf("%d\n",ans);
		scanf("%d%d",&n,&k);
	}
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324917331&siteId=291194637