码迷,mamicode.com
首页 > 其他好文 > 详细

松鼠的新家 (lca+树上差分)或(树链剖分)

时间:2020-03-13 13:03:06      阅读:50      评论:0      收藏:0      [点我收藏+]

标签:can   nod   要求   col   想法   name   str   image   add   

题目链接:https://www.luogu.com.cn/problem/P3258

题意:给出一个n  再给出走这n个点的顺序,再给出这n个点的连接方式(n-1条边,形成树)

思路:我们考虑lca+树上差分,首先介绍一下树上差分;

树上差分:想法跟普通的差不多,举个例子:假如我们要在某节点以及其到根节点所设计的节点都加上1;

    我们就只需要在某节点加上1即可(用数组p来表示)

    然后本题要求:假如从a走到b  我们则需要如下操作:

              技术图片

 

      这样得出的答案就是这一条路径都+1;

那么本题呢,就需要再求lca,这里我们用倍增法;

求出最后答案后,我们再将重复走的点--即可;

因为走的方式是  (a,b) (b,c) (c,d)  所以中间的点(除去左右端点)我们在计算的时候多算了一次,减去 ,而最后一个节点题目中有说明不需要放置糖果,所以也减去

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=3e5+10;
 4 struct node
 5 {
 6     int v;
 7     int nxt;
 8 }G[maxn<<1];
 9 int f[maxn][30]; int dep[maxn];
10 int b[maxn];
11 int head[maxn];int num=-1;
12 int p[maxn];
13 void add(int u,int v)
14 {
15     G[++num].v=v;G[num].nxt=head[u];head[u]=num;
16     G[++num].v=u;G[num].nxt=head[v];head[v]=num;
17 }
18 void dfs(int u,int father)//对应深搜预处理f数组
19 {
20     dep[u]=dep[father]+1;
21     for(int i=1;(1<<i)<=dep[u];i++){
22         f[u][i]=f[f[u][i-1]][i-1];
23     }
24     for(int i=head[u];i!=-1;i=G[i].nxt){
25         int v=G[i].v;
26         if(v==father)continue;//双向图需要判断是不是父亲节点
27         f[v][0]=u;
28         dfs(v,u);
29     }
30 }
31 int lca(int x,int y)
32 {
33     if(dep[x]<dep[y]) swap(x,y);
34     for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层
35     {
36         if(dep[f[x][i]]>=dep[y])
37             x=f[x][i];
38         if(x==y)return x;
39     }
40     for(int i=20;i>=0;i--)//从大到小枚举
41     {
42         if(f[x][i]!=f[y][i])//尽可能接近
43         {
44             x=f[x][i];y=f[y][i];
45         }
46     }
47     return f[x][0];//随便找一个**输出
48 }
49 void solve(int x,int fa){
50     for(int i=head[x];i!=-1;i=G[i].nxt){
51         if(fa==G[i].v)    continue;
52         solve(G[i].v,x);
53         p[x]+=p[G[i].v];
54     }
55 }
56 int main()
57 {
58     int n;
59     memset(head,-1,sizeof(head));
60     scanf("%d",&n);
61     for(int i=1;i<=n;i++)
62         scanf("%d",&b[i]);
63     for(int i=1;i<n;i++){
64         int x,y;
65         scanf("%d%d",&x,&y);
66         add(x,y);
67     }
68     dfs(1,0);
69     for(int i=1;i<n;i++){
70         p[b[i]]++;p[b[i+1]]++;
71         int tmp=lca(b[i],b[i+1]);
72         p[tmp]--;
73         p[f[tmp][0]]--;
74     }
75     solve(1,0);
76     for(int i=2;i<=n;i++) p[b[i]]--;
77     for(int i=1;i<=n;i++)
78         printf("%d\n",p[i]);
79     //printf("\n");
80 }

 

松鼠的新家 (lca+树上差分)或(树链剖分)

标签:can   nod   要求   col   想法   name   str   image   add   

原文地址:https://www.cnblogs.com/pangbi/p/12485718.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!