[NOIP2016 提高组] 天天爱跑步(树上差分)

如果没有时间的限制,这题就是对每个点 i i i,求经过 i i i的路径数,用树上差分解决即可:

枚举路径 x → y { x\to y\{ xy{

a [ x ] + = 1 ; a [ y ] + = 1 ; a[x]+=1;a[y]+=1; a[x]+=1;a[y]+=1;
a [ l c a ( x , y ) ] − = 1 ; a [ f a [ l c a ( x , y ) ] ] − = 2 ; a[lca(x,y)]-=1;a[fa[lca(x,y)]]-=2; a[lca(x,y)]=1;a[fa[lca(x,y)]]=2;

} \} }

枚举点 i { i\{ i{

经过 i i i的路径数 = 以 i i i为根的子树中 a a a的和

} \} }

(用树状数组实现)

考虑加上时间限制怎么做:

我们把每条路径 x → y x\to y xy拆成上行段和下行段。

  • 若点 i i i x → y x\to y xy的上行段上,
    i i i点的观察员看到从 x x x出发跑到 y y y的玩家,当且仅当
    d e p [ x ] − d e p [ i ] = w [ i ] dep[x]-dep[i]=w[i] dep[x]dep[i]=w[i] d e p [ i ] + w [ i ] = d e p [ x ] dep[i]+w[i]=dep[x] dep[i]+w[i]=dep[x]

  • 若点 i i i x → y x\to y xy的下行段上,
    i i i点的观察员看到从 x x x出发跑到 y y y的玩家,当且仅当
    d e p [ x ] + d e p [ y ] − 2 d e p [ l c a ( x , y ) ] − ( d e p [ y ] − d e p [ i ] ) = w [ i ] dep[x]+dep[y]-2dep[lca(x,y)]-(dep[y]-dep[i])=w[i] dep[x]+dep[y]2dep[lca(x,y)](dep[y]dep[i])=w[i]
    d e p [ i ] − w [ i ] = 2 d e p [ l c a ( x , y ) ] − d e p [ x ] dep[i]-w[i]=2dep[lca(x,y)]-dep[x] dep[i]w[i]=2dep[lca(x,y)]dep[x]

对于路径 x → y x\to y xy,我们将其拆成 上行段 p : x → l c a ( x , y ) p:x\to lca(x,y) p:xlca(x,y) x x x方向上的儿子,下行段 q : l c a ( x , y ) → y q:lca(x,y)\to y q:lca(x,y)y,并记 v [ p ] = d e p [ x ] v[p]=dep[x] v[p]=dep[x] v [ q ] = 2 d e p [ l c a ( x , y ) ] − d e p [ x ] v[q]=2dep[lca(x,y)]-dep[x] v[q]=2dep[lca(x,y)]dep[x]

对于点 i i i,我们记 v p [ i ] = d e p [ i ] + w [ i ] v_p[i]=dep[i]+w[i] vp[i]=dep[i]+w[i] v q [ i ] = d e p [ i ] − w [ i ] v_q[i]=dep[i]-w[i] vq[i]=dep[i]w[i]

那么 i i i点的观察员看到的玩家数 = ∑ \sum 经过 i i i且满足 v [ p ] = v p [ i ] v[p]=v_p[i] v[p]=vp[i]的上行段 p p p的数量 + ∑ \sum 经过 i i i且满足 v [ q ] = v q [ i ] v[q]=v_q[i] v[q]=vq[i]的下行段 q q q的数量

先把点按 v p [ i ] v_p[i] vp[i]排序,把上行段按 v [ p ] v[p] v[p]排序,按树上差分的套路计算上行段的贡献。

再把点按 v q [ i ] v_q[i] vq[i]排序,把下行段按 v [ q ] v[q] v[q]排序,按树上差分的套路计算下行段的贡献。

如此即可得到最终答案。

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
const int N=1e6+10;
struct Edge{
    
    
	int v,nxt;
}edge[N<<1];
int n,m,w[N],cnt,head[N],ans[N];
int ind,dfn[N],siz[N],dep[N],fa[N][20]; 
struct Query{
    
    
	int nd,x;
	friend bool operator < (Query a,Query b){
    
    
		return a.x<b.x;
	}
}a[N<<1];
struct Data{
    
    
	int d,u,x;
	friend bool operator < (Data a,Data b){
    
    
		return a.x<b.x;
	}
}b[2][N];
int tot[2];
stack<Data> s;
void addedge(int u,int v){
    
    
	edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u){
    
    
	dfn[u]=++ind;
	siz[u]=1;
	for(int i=1;i<=19;i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=edge[i].nxt){
    
    
		int v=edge[i].v;
		if(v==fa[u][0]) continue;
		fa[v][0]=u;
		dep[v]=dep[u]+1;
		dfs(v);
		siz[u]+=siz[v];
	}
}
int LCA(int u,int v){
    
    
	if(dep[u]<dep[v]) swap(u,v);
	int diff=dep[u]-dep[v];
	for(int i=19;i>=0;i--){
    
    
		if(diff&(1<<i)) u=fa[u][i];
	}
	if(u==v) return u;
	for(int i=19;i>=0;i--){
    
    
		if(fa[u][i]!=fa[v][i]){
    
    
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int c[N];
int lowbit(int x){
    
    return x&(-x);}
void add(int x,int v){
    
    
	if(!x) return;
	for(int i=x;i<=n;i+=lowbit(i)) c[i]+=v;
}
int sum(int x){
    
    
	int res=0;
	for(int i=x;i;i-=lowbit(i)) res+=c[i];
	return res;
}
int main(){
    
    
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++){
    
    
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	dep[1]=1;dfs(1);
	for(int i=1;i<=n;i++){
    
    
		scanf("%d",&w[i]);
		a[i]=(Query){
    
    i,dep[i]+w[i]};
		a[i+n]=(Query){
    
    i,dep[i]-w[i]};
	}
	sort(a+1,a+n+1);
	sort(a+n+1,a+2*n+1);
	for(int i=1;i<=m;i++){
    
    
		int s,t,lca;
		scanf("%d%d",&s,&t);
		lca=LCA(s,t);
		if(s==lca){
    
    
			b[1][++tot[1]]=(Data){
    
    t,s,dep[s]};
		}
		else if(t==lca){
    
    
			b[0][++tot[0]]=(Data){
    
    s,t,dep[s]};
		}
		else{
    
    
			int son=s;
			for(int i=19;i>=0;i--){
    
    
				if(dep[fa[son][i]]>dep[lca]) son=fa[son][i];
			}
			b[0][++tot[0]]=(Data){
    
    s,son,dep[s]};
			b[1][++tot[1]]=(Data){
    
    t,lca,2*dep[lca]-dep[s]};
		}
	}
	sort(b[0]+1,b[0]+tot[0]+1);
	sort(b[1]+1,b[1]+tot[1]+1);
	int p=1;
	for(int i=1;i<=n;i++){
    
    
		if(a[i].x!=a[i-1].x){
    
    
			while(!s.empty()){
    
    
				Data tmp=s.top();s.pop();
				add(dfn[fa[tmp.u][0]],1);
				add(dfn[tmp.d],-1);
			}
		}
		for(;p<=tot[0]&&b[0][p].x<=a[i].x;p++){
    
    
			if(a[i].x!=a[i-1].x&&b[0][p].x==a[i].x){
    
    
				Data tmp=b[0][p];
				add(dfn[fa[tmp.u][0]],-1);
				add(dfn[tmp.d],1);
				s.push(tmp);
			}
		}
		ans[a[i].nd]+=sum(dfn[a[i].nd]+siz[a[i].nd]-1)-sum(dfn[a[i].nd]-1);
	}
	while(!s.empty()){
    
    
		Data tmp=s.top();s.pop();
		add(dfn[fa[tmp.u][0]],1);
		add(dfn[tmp.d],-1);
	}
	p=1;
	for(int i=n+1;i<=2*n;i++){
    
    
		if(a[i].x!=a[i-1].x){
    
    
			while(!s.empty()){
    
    
				Data tmp=s.top();s.pop();
				add(dfn[fa[tmp.u][0]],1);
				add(dfn[tmp.d],-1);
			}
		}
		for(;p<=tot[1]&&b[1][p].x<=a[i].x;p++){
    
    
			if(a[i].x!=a[i-1].x&&b[1][p].x==a[i].x){
    
    
				Data tmp=b[1][p];
				add(dfn[fa[tmp.u][0]],-1);
				add(dfn[tmp.d],1);
				s.push(tmp);
			}
		}
		ans[a[i].nd]+=sum(dfn[a[i].nd]+siz[a[i].nd]-1)-sum(dfn[a[i].nd]-1);
	}
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Emma2oo6/article/details/120699245