天天爱跑步

题目链接:P1600 天天爱跑步

暴力程序(25pts) 复杂度\(O(n^2)\)

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
int n,m,ans[maxn];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
inline void add(int x,int y){
	e++;nex[e]=beg[x];
	beg[x]=e;to[e]=y;
}
int dep[maxn],f[maxn][20]; 
inline void dfs(int x,int fa){
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	for(int i=1;i<=19;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=beg[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa)continue;
		dfs(t,x);
	}
}
inline int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=19;i>=0;i--)
		if(dep[f[x][i]]>=dep[y])x=f[x][i];
	if(x==y)return x;
	for(int i=19;i>=0;i--)
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	return f[x][0];
}
int s[maxn],t[maxn],anc[maxn],w[maxn];
int main(){
	n=read(),m=read();
	int x,y;
	for(int i=1;i<n;i++){
		x=read(),y=read();
		add(x,y),add(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
		w[i]=read();
	for(int i=1;i<=m;i++){
		s[i]=read(),t[i]=read();
		anc[i]=lca(s[i],t[i]);
		x=0,y=dep[s[i]]+dep[t[i]]-2*dep[anc[i]];
		for(int j=s[i];j!=anc[i];j=f[j][0],x++)
			if(w[j]==x)ans[j]++;
		for(int j=t[i];j!=anc[i];j=f[j][0],y--)
			if(w[j]==y)ans[j]++;
		if(w[anc[i]]==dep[s[i]]-dep[anc[i]])
			ans[anc[i]]++;
	}
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	puts("");
	return 0;
}

考虑如何优化。

考虑一个点\(x\)在路径\(s->t\)上,则分两种情况讨论:

1.若\(x\)\(s->lca\)上,则需满足条件\(dep[s]-dep[x]=w[x]\)时才能观察到,即\(dep[x]+w[x]=dep[s]\)

2.若\(x\)\(lca->t\)上,则需满足条件\(dis_{s,t}-(dep[t]-dep[x])=w[x]\)时才能观察到,即\(dis_{s,t}-dep[t]=w[x]-dep[x]\)

注意:若\(dep[lca]+w[lca]=dep[s]\)\(lca\)会被计算两次,需减去一次。

由于等式两边无直接联系,考虑使用线段树合并。

注意:在\(dep[x]<dep[lca]\)时,\(x\)不在\(s->t\)上,故应在\(f[lca]\)处消除这一条边的贡献,其思想类似于树上差分。

完整代码如下: 复杂度\(O(n\log n)\)

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
int n,m,ans[maxn];
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
inline void add(int x,int y){
	e++;nex[e]=beg[x];
	beg[x]=e;to[e]=y;
}
int dep[maxn],f[maxn][20]; 
inline void dfs(int x,int fa){
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	for(int i=1;i<=19;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=beg[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa)continue;
		dfs(t,x);
	}
}
inline int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=19;i>=0;i--)
		if(dep[f[x][i]]>=dep[y])x=f[x][i];
	if(x==y)return x;
	for(int i=19;i>=0;i--)
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	return f[x][0];
}
/*
if x on s->lca dep[x]+w[x]=dep[s]
if x on lca->t dis-(dep[t]-dep[x])=w[x]
	=>dis-dep[t]+n=w[x]-dep[x]+n
*/
struct node{
	int sv,tv,l,r;
}tr[maxn*50];
int cnt,rt[maxn];
inline int update_s(int h,int l,int r,int x,int y){
	if(!h)h=++cnt;
	tr[h].sv+=y;
	if(l==r)return h;
	int mid=(l+r)>>1;
	if(mid>=x)tr[h].l=update_s(tr[h].l,l,mid,x,y);
	else tr[h].r=update_s(tr[h].r,mid+1,r,x,y);
	return h;
}
inline int update_t(int h,int l,int r,int x,int y){
	if(!h)h=++cnt;
	tr[h].tv+=y;
	if(l==r)return h;
	int mid=(l+r)>>1;
	if(mid>=x)tr[h].l=update_t(tr[h].l,l,mid,x,y);
	else tr[h].r=update_t(tr[h].r,mid+1,r,x,y);
	return h;
}
int anc[maxn],dis[maxn],w[maxn];
inline int merge(int s,int t,int l,int r){
	if(!s||!t)return s+t;
	if(l==r){
		tr[s].sv+=tr[t].sv;
		tr[s].tv+=tr[t].tv;
		return s;
	}
	int mid=(l+r)>>1;
	tr[s].l=merge(tr[s].l,tr[t].l,l,mid);
	tr[s].r=merge(tr[s].r,tr[t].r,mid+1,r);
	return s;
}
inline int query_s(int h,int l,int r,int x){
	if(!h)return 0;
	if(l==r)return tr[h].sv;
	int mid=(l+r)>>1;
	if(mid>=x)return query_s(tr[h].l,l,mid,x);
	else return query_s(tr[h].r,mid+1,r,x);
}
inline int query_t(int h,int l,int r,int x){
	if(!h)return 0;
	if(l==r)return tr[h].tv;
	int mid=(l+r)>>1;
	if(mid>=x)return query_t(tr[h].l,l,mid,x);
	else return query_t(tr[h].r,mid+1,r,x);
}
inline void solve(int x,int fa){
	for(int i=beg[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa)continue;
		solve(t,x);
		rt[x]=merge(rt[x],rt[t],0,2*n);
	}
	ans[x]+=query_s(rt[x],0,2*n,dep[x]+w[x]);
	ans[x]+=query_t(rt[x],0,2*n,w[x]-dep[x]+n);
}
int s[maxn],t[maxn];
int main(){
	n=read(),m=read();
	int x,y;
	for(int i=1;i<n;i++){
		x=read(),y=read();
		add(x,y),add(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
		w[i]=read();
	for(int i=1;i<=m;i++){
		s[i]=read(),t[i]=read();
		anc[i]=lca(s[i],t[i]);
		dis[i]=dep[s[i]]+dep[t[i]]-2*dep[anc[i]];
		if(w[anc[i]]==dep[s[i]]-dep[anc[i]])ans[anc[i]]--;
		rt[s[i]]=update_s(rt[s[i]],0,2*n,dep[s[i]],1);
		rt[t[i]]=update_t(rt[t[i]],0,2*n,dis[i]-dep[t[i]]+n,1);
		rt[f[anc[i]][0]]=update_s(rt[f[anc[i]][0]],0,2*n,dep[s[i]],-1);
		rt[f[anc[i]][0]]=update_t(rt[f[anc[i]][0]],0,2*n,dis[i]-dep[t[i]]+n,-1);
	}
	solve(1,0);
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	puts("");
	return 0;
}

深深地感到自己的弱小。

posted @ 2020-09-28 20:50  syzf2222  阅读(175)  评论(0编辑  收藏  举报