[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\)

  1. x在上升的路径上(u->lca)
  2. 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;
}

posted @ 2018-10-12 08:34  GhostCai  阅读(108)  评论(0编辑  收藏  举报