●CodeForce 293E Close Vertices

题链:

http://codeforces.com/contest/293/problem/E
题解:

点分治,树状数组
大致思路和 POJ 1741 那道点分治入门题相同,
只是因为多了一个路径的边数限制,
所以在统计答案时,
要用数据结构维护一下在满足距离限制的情况下,有多少点也满足边数限制。
树状数组维护到当前的根(重心)的距离为x时的点的个数。
在calc函数中,记录dep[u]表示u到当前的根(重心)的边数,
然后统计u号点可以和多少点组成合法点对时,就查询树状数中有多少点满足到根的距离小于等于W-dep[u].(W是输入的边数限制)


代码:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
typedef pair<int,int>pii;
struct EDGE{
	int ent;
	int to[MAXN*2],nxt[MAXN*2],val[MAXN*2],head[MAXN];
	void Reset(){ent=2; memset(head,0,sizeof(head));}
	void Adde(int u,int v,int w){
		to[ent]=v; val[ent]=w; nxt[ent]=head[u]; head[u]=ent++;
		to[ent]=u; val[ent]=w; nxt[ent]=head[v]; head[v]=ent++;
	}
}E;
struct BIT{
	int val[MAXN],N;
	int Lowbit(int x){return x&-x;}
	void Reset(int n){
		N=n+1; //memset(val,0,sizeof(val));
	}
	void Modify(int p,int x){
		p++; for(;p<=N;p+=Lowbit(p)) val[p]+=x;
	}
	int Query(int p){
		static int ans; ans=0; p++;
		for(;p;p-=Lowbit(p)) ans+=val[p];
		return ans;
	}
}DT;
int N,K,W;
long long ANS;
int size[MAXN];
bool vis[MAXN];
void getroot(int u,int dad,int num,int &root,int &rootnum){
	int maxnum=0; size[u]=0;
	for(int i=E.head[u];i;i=E.nxt[i]){
		if(E.to[i]==dad||vis[E.to[i]]) continue;
		getroot(E.to[i],u,num,root,rootnum);
		size[u]+=size[E.to[i]];
		maxnum=max(maxnum,size[E.to[i]]);
	}
	size[u]++; maxnum=max(maxnum,num-size[u]);
	if(maxnum<rootnum) root=u,rootnum=maxnum;
}
long long calc(int s,int len,int deep){
	long long ret=0;
	static pii A[MAXN];
	static int dis[MAXN],dep[MAXN],reach[MAXN],rnt,ant;
	static queue<int>Q;
	ant=0; rnt++; Q.push(s);
	dis[s]=len; reach[s]=rnt; dep[s]=deep;
	while(!Q.empty()){
		int u=Q.front(); Q.pop();
		A[++ant]=make_pair(dis[u],dep[u]);
		for(int i=E.head[u];i;i=E.nxt[i]){
			int v=E.to[i];
			if(reach[v]==rnt||vis[v]) continue;
			dis[v]=dis[u]+E.val[i];
			dep[v]=dep[u]+1;
			reach[v]=rnt; Q.push(v);
		}
	}
	sort(A+1,A+ant+1);
	for(int i=1;i<=ant;i++) DT.Modify(A[i].second,1);
	int l=1,r=ant;
	while(l<=r){
		if(A[l].first+A[r].first>K) DT.Modify(A[r].second,-1),r--;
		else DT.Modify(A[l].second,-1),ret+=(W-A[l].second>=0?DT.Query(W-A[l].second):0),l++;
	}
	return ret;
}
void divide(int u){
	int root=u,rootnum=size[u];
	getroot(u,0,size[u],root,rootnum);
	vis[root]=1;
	ANS+=calc(root,0,0);
	for(int i=E.head[root];i;i=E.nxt[i]) if(!vis[E.to[i]])
		ANS-=calc(E.to[i],E.val[i],1);
	for(int i=E.head[root];i;i=E.nxt[i]) if(!vis[E.to[i]])
		divide(E.to[i]);
}
void read(int &x){
	static int sign; static char ch;
	x=0; sign=1; ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')sign=-1;ch=getchar();}
	while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	x=x*sign;
}
int main(){
	read(N); read(W); read(K);
	E.Reset(); DT.Reset(N); ANS=0;
	for(int i=2,dad,w;i<=N;i++)
	read(dad),read(w),E.Adde(dad,i,w);
	size[1]=N; divide(1);
	cout<<ANS<<endl;
	return 0;
}

  

posted @ 2018-03-10 20:44  *ZJ  阅读(142)  评论(0编辑  收藏  举报