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

bzoj3631: [JLOI2014]松鼠的新家(LCA+差分)

时间:2016-11-17 10:26:59      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:printf   ext   continue   span   name   子节点   差分   int   node   

题目大意:一棵树,以一定顺序走完n个点,求每个点经过多少遍

可以树链剖分,也可以直接在树上做差分序列的标记

后者打起来更舒适一点。。

具体实现:

先求x,y的lca,且dep[x]<dep[y],

如果在一棵子树下的一条链上,那么lca就是x

则g[fa[x]]--; g[y]++;

如果在一棵子树的两条分枝上,那么lca设为z

g[x]++, g[y]++, g[z]--, g[fa[z]]--

最后从叶子节点加回根节点,加法是差分序列的那种加法

因为z会加左右两边,多加了1,所以要减去。

 1 #include<stdio.h>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn = 300010;
 5 struct node{
 6     int to,next;
 7 }e[maxn*2];
 8 int n,a[maxn],head[maxn],dep[maxn],fa[maxn][20],w[maxn],f[maxn],tot,logn;
 9 
10 void insert(int u, int v){
11     e[++tot].to=v; e[tot].next=head[u]; head[u]=tot;
12 }
13 
14 void dfs(int u, int f, int d){
15     dep[u]=d; fa[u][0]=f;
16     for (int i=1; i<=logn; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
17     for (int i=head[u]; i; i=e[i].next)
18         if (e[i].to!=f) dfs(e[i].to,u,d+1);
19 }
20 
21 void lca(int u, int v){
22     if (dep[u]<dep[v]) swap(u,v);
23     int x=u,y=v;
24     while (dep[u]>dep[v]){
25         for (int i=logn; i>=0; i--)
26             if (dep[fa[u][i]]>dep[v])
27                 u=fa[u][i];
28         u=fa[u][0];
29     }
30     if (u==v){  //在某条链上 
31         w[fa[u][0]]--;
32         w[x]++;
33         return;
34     }
35     for (int i=logn; i>=0; i--)  //在分叉口上 
36         if (fa[u][i]!=fa[v][i]){
37             u=fa[u][i];
38             v=fa[v][i];
39         }
40     u=fa[u][0];
41     w[x]++; w[y]++;
42     w[u]--; w[fa[u][0]]--;
43     return; 
44 }
45 
46 void get_ans(int u){
47     f[u]=w[u];// printf("  %d\n", w[u]);
48     for (int i=head[u],v; i; i=e[i].next){
49         if ((v=e[i].to)==fa[u][0]) continue;
50         get_ans(e[i].to);
51         f[u]+=f[v];
52     }
53 }
54 
55 int main(){
56     scanf("%d", &n);
57     for (int i=1; i<=n; i++) scanf("%d", &a[i]); tot=1; while ((1<<logn)<n) logn++;
58     for (int i=1,u,v; i<n; i++) scanf("%d%d", &u, &v),insert(u,v),insert(v,u); insert(0,a[1]);
59     dfs(0,0,1);
60     for (int i=2; i<=n; i++){
61         lca(a[i-1],a[i]);
62     }
63     get_ans(a[1]);
64     for (int i=1; i<=n; i++) printf("%d\n", (i==a[1])?f[i]:f[i]-1);
65     return 0;
66 }

 

bzoj3631: [JLOI2014]松鼠的新家(LCA+差分)

标签:printf   ext   continue   span   name   子节点   差分   int   node   

原文地址:http://www.cnblogs.com/mzl120918/p/6072335.html

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