NOIP2016 天天爱跑步(树上差分)

题意

给定一棵树,从时刻 0 开始,有若干人从 S[i] 出发向 T[i] 移动,每单位时刻移动一条边

对于树上每个点 x,求 w[x]  时刻有多少人恰好路过 x

N,M≤300000

题解

从上午11点做到下午3点45终于做出来了。

一开始坚持自己的想法,发现错了之后不知道怎么改,无奈看了题解。

列出恰好路过的条件并化简
在 Si 到 lca(Si,Ti ) 阶段,应满足 d[Si ]=w[x]+d[x]
在 lca(Si,Ti ) 到 Ti阶段,应满足 d[Si]-2∗d[lca(Si,Ti )]=w[x]-d[x]
相当于在 Si 位置出现一个 A 类数 d[Si ],在 lca(Si,Ti ) 的父节点消失
在 Ti 位置出现一个 B 类数 d[Si ]-2∗d[lca(Si,Ti )],在 lca(Si,Ti ) 消失
求子树 x 中,等于 w[x]+d[x] 的 A 类数个数 + 等于 w[x]-d[x] 的 B 类数个数
全局数组计数,统计遍历子树 x 前后相应位置上的差我一开始就是没注意这死活调不出来
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<vector>
  7 using namespace std;
  8 const int N=300010;
  9 vector<int> v1[N],v2[N],v3[N],v4[N];
 10 int cnt,head[N];
 11 int fa[N][32],dep[N];
 12 int book1[N],book2[N*2];
 13 int n,m,w[N],ans[N];
 14 struct edge{
 15     int to,nxt;
 16 }e[N*2];
 17 void add(int u,int v){
 18     cnt++;
 19     e[cnt].nxt=head[u];
 20     e[cnt].to=v;
 21     head[u]=cnt;
 22 }
 23 void dfs1(int u,int f,int deep){
 24     fa[u][0]=f;
 25     dep[u]=deep;
 26     for(int i=head[u];i;i=e[i].nxt){
 27         int v=e[i].to;
 28         if(v==f)continue;
 29         dfs1(v,u,deep+1);
 30     }
 31 }
 32 int lca(int u,int v){
 33     if(dep[u]<dep[v])swap(u,v);
 34     for(int i=30;i>=0;i--){
 35         if(dep[fa[u][i]]>=dep[v])u=fa[u][i];
 36     }
 37     if(u==v)return u;
 38     for(int i=30;i>=0;i--){
 39         if(fa[u][i]!=fa[v][i]){
 40             u=fa[u][i];v=fa[v][i];
 41         }
 42     }
 43     return fa[u][0];
 44 }
 45 void dfs2(int u){
 46     ans[u]=book1[w[u]+dep[u]]+book2[w[u]-dep[u]+N];
 47     for(int i=0;i<v1[u].size();i++){
 48         book1[v1[u][i]]++;
 49     }
 50     for(int i=0;i<v2[u].size();i++){
 51         book1[v2[u][i]]--;
 52     }
 53     for(int i=0;i<v3[u].size();i++){
 54         book2[v3[u][i]]++;
 55     }
 56     for(int i=0;i<v4[u].size();i++){
 57         book2[v4[u][i]]--;
 58     }
 59     for(int i=head[u];i;i=e[i].nxt){
 60         int v=e[i].to;
 61         if(v==fa[u][0])continue;
 62         dfs2(v);
 63     }
 64     ans[u]=book1[w[u]+dep[u]]+book2[w[u]-dep[u]+N]-ans[u];
 65 }
 66 int main(){
 67     scanf("%d%d",&n,&m);
 68     for(int i=1;i<=n-1;i++){
 69         int u,v;
 70         scanf("%d%d",&u,&v);
 71         add(u,v);
 72         add(v,u);
 73     }
 74     dfs1(1,0,1);
 75     for(int i=1;i<=30;i++)
 76         for(int j=1;j<=n;j++)
 77             fa[j][i]=fa[fa[j][i-1]][i-1];
 78     for(int i=1;i<=n;i++){
 79         scanf("%d",&w[i]);
 80     }
 81     for(int i=1;i<=m;i++){
 82         int u,v;
 83         scanf("%d%d",&u,&v);
 84         int c=lca(u,v);
 85         v1[u].push_back(dep[u]);
 86         v2[fa[c][0]].push_back(dep[u]);
 87         v3[v].push_back(dep[u]-2*dep[c]+N);
 88         v4[c].push_back(dep[u]-2*dep[c]+N);
 89     }
 90     for(int i=0;i<v1[0].size();i++){
 91         book1[v1[0][i]]++;
 92     }
 93     for(int i=0;i<v2[0].size();i++){
 94         book1[v2[0][i]]--;
 95     }
 96     for(int i=0;i<v3[0].size();i++){
 97         book2[v3[0][i]]++;
 98     }
 99     for(int i=0;i<v4[0].size();i++){
100         book2[v4[0][i]]--;
101     }
102     dfs2(1);
103     for(int i=1;i<=n;i++){
104         printf("%d ",ans[i]);
105     }
106     return 0;
107 }
View Code

 

 

posted @ 2018-07-29 15:53  Xu-daxia  阅读(146)  评论(0编辑  收藏  举报