[NOIP2016]天天爱跑步

NOIP2016D1T2......

我连D1T2都需要看题解才能做了......

AFO......

题目传送门

解析:

考虑有一个玩家,其起点为$u$,终点为$v$。

则其路径可以分成两部分,一部分为$u->lca(u,v)$,另一部分为$lca(u,v)->v$

对于前半部分,可以对点x(x在从下至上的路径上)产生贡献当且仅当$dis(u,x)=w_x$

由于边权均为1,因此它可以化简为$dep_u-dep_x=w_x$,然后移项得$dep_u=dep_x+w_x$

对于后半部分,当且仅当$dis(u,v)-dis(x,v)=w_x$时,可以产生贡献,化简得

$dep_u-2*dep_lca(u,v)=w_x-dep_x$.

因此可以使用树上差分维护一些桶,然后取每个点被贡献的总数,对恰好在LCA的点要-1(会被计算两次)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<vector>
 5 #define N 600005
 6 using namespace std;
 7 int read()
 8 {
 9     int x=0,f=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
12     return x*f;
13 }
14 struct tag{int v,siz;};
15 int n,m,w[N],s[N],t[N],LCA[N],fa[N][21],T1[N+N],T2[N+N],father[N],dep[N],cnt[N];
16 vector<int>G[N];
17 vector<tag>tag1[N],tag2[N];
18 void dfs1(int x)
19 {
20     dep[x]=dep[father[x]]+1;
21     for(int i=0;i<=19;i++)fa[x][i+1]=fa[fa[x][i]][i];
22     int sz=G[x].size(); 
23     for(int i=0;i<sz;i++)
24     {
25         if(G[x][i]==father[x])continue;
26         father[G[x][i]]=fa[G[x][i]][0]=x;
27         dfs1(G[x][i]);
28     }
29 }
30 int lca(int x,int y)
31 {
32     if(dep[x]<dep[y])swap(x,y);
33     for(int i=20;i>=0;i--)
34     {
35         if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
36         if(x==y)return x;
37     }
38     for(int i=20;i>=0;i--)
39     {
40         if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
41     }
42     return fa[x][0]; 
43 }
44 void dfs(int x,int a,int b)
45 {
46     int sz=tag1[x].size();
47     for(int i=0;i<sz;i++)T1[tag1[x][i].v+N]+=tag1[x][i].siz;
48     sz=tag2[x].size();
49     for(int i=0;i<sz;i++)T2[tag2[x][i].v+N]+=tag2[x][i].siz;
50     sz=G[x].size();
51     for(int i=0;i<sz;i++)
52     {
53         if(G[x][i]==father[x])continue;
54         dfs(G[x][i],T1[w[G[x][i]]+dep[G[x][i]]+N],T2[w[G[x][i]]-dep[G[x][i]]+N]);
55     }
56     cnt[x]+=T1[w[x]+dep[x]+N]+T2[w[x]-dep[x]+N]-a-b;
57 }
58 int main()
59 {
60     n=read();m=read();
61     for(int x,y,i=1;i<n;i++)
62     {
63         x=read();y=read();
64         G[x].push_back(y);
65         G[y].push_back(x);
66     }
67     for(int i=1;i<=n;i++)w[i]=read();
68     dfs1(1);
69     for(int i=1;i<=m;i++)s[i]=read(),t[i]=read(),LCA[i]=lca(s[i],t[i]);
70     for(int i=1;i<=m;i++)
71     {
72         if(w[LCA[i]]+dep[LCA[i]]==dep[s[i]])--cnt[LCA[i]];
73         tag1[s[i]].push_back((tag){dep[s[i]],1});
74         tag1[father[LCA[i]]].push_back((tag){dep[s[i]],-1});
75         tag2[t[i]].push_back((tag){dep[s[i]]-2*dep[LCA[i]],1});
76         tag2[father[LCA[i]]].push_back((tag){dep[s[i]]-2*dep[LCA[i]],-1});
77     }
78     dfs(1,0,0);
79     for(int i=1;i<=n;i++)printf("%d ",cnt[i]);
80     return 0;
81 }
82 //up:dep[s]=w[i]+dep[i];
83 //down:dis(s,t)-(dep[t]-dep[i])=w[i];
84 //=>dep[s]+dep[t]-2*dep[lca(s,t)]-dep[t]+dep[i]=w[i];
85 //=>dep[s]-2*dep[lca(s,t)]=w[i]-dep[i]
View Code
原文地址:https://www.cnblogs.com/szmssf/p/11588019.html