LCA+树上差分天天爱跑步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA+树上差分天天爱跑步相关的知识,希望对你有一定的参考价值。

困扰我半年多的题终于做出来了

一开始我的做法是想在回溯的时候统计答案,但是各个分支之间又会相互影响,然后就不会做了

看完别人的题解后发现用桶的前后状态做差来统计答案更简单

 1 #include <cstdio>
 2 #include <vector>
 3 #include <iostream>
 4 #define db(x) cout<<#x<<"="<<x<<endl; 
 5 using namespace std;
 6 const int N=300010;
 7 typedef pair<int,int> P;
 8 struct E{
 9     int next,to;
10 }e[2*N];
11 int n,m,a,b,sz=0,head[N],w[N],dep[N],fa[N][20],chk1[3*N],chk2[3*N],ans[N];
12 vector<int> p1[N],p2[N],q1[N],q2[N];
13 void insert(int a,int b)
14 {
15     sz++;
16     e[sz].next=head[a];
17     head[a]=sz;
18     e[sz].to=b;
19 }
20 void dfs(int x,int f)
21 {
22     for (int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
23     for (int i=head[x];i;i=e[i].next)
24         if (e[i].to!=f)
25         {
26             dep[e[i].to]=dep[x]+1;
27             fa[e[i].to][0]=x;
28             dfs(e[i].to,x);
29         }
30 }
31 int lca(int a,int b)
32 {
33     if (dep[a]<dep[b]) swap(a,b);
34     int t=dep[a]-dep[b];
35     for (int i=19;i>=0;i--)
36         if (t&(1<<i)) a=fa[a][i];
37     for (int i=19;i>=0;i--)
38         if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
39     if (a==b) return a;
40     return fa[a][0];
41 }
42 int solve(int x,int f)
43 {
44     int s=chk1[N+dep[x]+w[x]]+chk2[N+dep[x]-w[x]];
45     for (int i=0;i<p1[x].size();i++) chk1[N+p1[x][i]]++;
46     for (int i=0;i<p2[x].size();i++) chk2[N+p2[x][i]]++;
47     for (int i=head[x];i;i=e[i].next)
48         if (e[i].to!=f) solve(e[i].to,x);
49     ans[x]+=chk1[N+dep[x]+w[x]]+chk2[N+dep[x]-w[x]]-s;
50     for (int i=0;i<q1[x].size();i++) chk1[N+q1[x][i]]--;
51     for (int i=0;i<q2[x].size();i++) chk2[N+q2[x][i]]--;
52 }
53 int main()
54 {
55     scanf("%d%d",&n,&m);
56     for (int i=1;i<n;i++)
57     {
58         scanf("%d%d",&a,&b);
59         insert(a,b);insert(b,a);
60     }
61     dfs(1,1);
62     for (int i=1;i<=n;i++) scanf("%d",&w[i]);
63     for (int i=1;i<=m;i++)
64     {
65         scanf("%d%d",&a,&b);
66         int s=lca(a,b);
67         if (w[s]==dep[a]-dep[s]) ans[s]--;
68         p1[a].push_back(dep[a]);
69         p2[b].push_back(-(dep[a]-2*dep[s]));
70         q1[s].push_back(dep[a]);
71         q2[s].push_back(-(dep[a]-2*dep[s]));
72     }
73     solve(1,1);
74     for (int i=1;i<=n;i++) printf("%d ",ans[i]);
75 }

 

以上是关于LCA+树上差分天天爱跑步的主要内容,如果未能解决你的问题,请参考以下文章

LCA+树上差分天天爱跑步

BZOJ 4719--天天爱跑步(LCA&差分)

[NOIp2016提高组]天天爱跑步

天天爱跑步

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

bzoj4719: [Noip2016]天天爱跑步 树上差分