[BZOJ] 4719: [Noip2016]天天爱跑步
弱化版题目:关联点
关联点1
统计:\(v\)在\(x\)的子树中,且\(dis(x,v)=a_v\)的\(v\)u
也就是要找一个点的k级祖先,可以在dfs时维护一个祖先栈,stack[top-a[v]]即为点x
关联点2
统计:\(v\)在\(x\)的子树中,且\(dis(x,v)=a_x\)的\(v\)
也就是找一个点的k级儿子,可以用全局的一个桶bac维护每个点的出现次数,先记录bac[a[x]]的值,对子树dfs后再用新的bac[a[x]]减去原答案即为k级儿子个数
本题
把路径拆开,统计每个点对答案的贡献
设从\(u\)到\(v\)的一条路径上有一点\(x\)
- x在上升的路径上(u->lca)
- x在下降的路径上(lca->v)
对于情况1,当且仅当\(dep[x]+w[x]=dep[u]\)成立,因此在每个\(u\)的位置开vector存\(dep[u]\),对于每个点x统计的是\(dep[x]+w[x]\)
对于情况2,当且仅当\(w[x]-dep[x]=dis(u,v)-dep[v]\)成立,因此在每个\(v\)的位置开vector存\(dis(u,v)-dep[v]\),对于每个点x统计的是\(w[x]-dep[x]\)
实际上这样会算重,lca的位置会重复贡献,因此还要开两个vector记录经过lca路径的起点和终点,也就是情况1、2统计的内容
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
const int MAXN = 300005;
int n,m,W[MAXN];
vector<int> v1[MAXN],v2[MAXN],v3[MAXN],v4[MAXN];
struct Edge{
int nex,to;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y){
e[++ecnt].nex = head[x];
e[ecnt].to = y;
head[x] = ecnt;
}
int fa[MAXN],hs[MAXN],dep[MAXN];
int sp1(int x,int pre){
// cout<<x<<endl;
fa[x]=pre;dep[x]=dep[pre]+1;
int mx=0,siz=1,tmp;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;
if(v==pre)continue;
tmp=sp1(v,x);siz+=tmp;
if(tmp>mx){mx=tmp;hs[x]=v;}
}
return siz;
}
int top[MAXN];
void sp2(int x,int tp){
top[x]=tp;
if(hs[x])sp2(hs[x],tp);
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;
if(v==fa[x]||v==hs[x])continue;
sp2(v,v);
}
}
int lca(int x,int y){
while(top[x]!=top[y])
dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
return dep[x]<dep[y]?x:y;
}
int bac[MAXN<<1],ans[MAXN];
const int offset=300005;
void dfs1(int x){
int pre=bac[dep[x]+W[x]];
int sz=v1[x].size();
for(int i=0;i<sz;i++)bac[v1[x][i]]++;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(v==fa[x])continue;
dfs1(v);
}
ans[x]+=bac[dep[x]+W[x]]-pre;
sz=v4[x].size();
for(int i=0;i<sz;i++)bac[v4[x][i]]--;
}
void dfs2(int x){
int pre=bac[W[x]-dep[x]+offset];
int sz=v2[x].size();
for(int i=0;i<sz;i++)bac[v2[x][i]+offset]++;
sz=v3[x].size();
for(int i=0;i<sz;i++)bac[v3[x][i]+offset]--;
for(int i=head[x];i;i=e[i].nex){
int v=e[i].to;if(v==fa[x])continue;
dfs2(v);
}
ans[x]+=bac[W[x]-dep[x]+offset]-pre;
}
int main(){
n=rd();m=rd();
int x,y;
for(int i=1;i<=n-1;i++){
x=rd();y=rd();
add(x,y);add(y,x);
}
sp1(1,0);sp2(1,1);
for(int i=1;i<=n;i++)W[i]=rd();
for(int i=1;i<=m;i++){
x=rd();y=rd();int l=lca(x,y);
v1[x].push_back(dep[x]);
v2[y].push_back((dep[x]-(dep[l]<<1)));
v3[l].push_back((dep[x]-(dep[l]<<1)));
v4[l].push_back(dep[x]);
}
dfs1(1);
memset(bac,0,sizeof(bac));
dfs2(1);
for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
return 0;
}
本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9776137.html