P3258 [JLOI2014]松鼠的新家

P3258 [JLOI2014]松鼠的新家
倍增lca+树上差分,从叶子节点向根节点求前缀和,dfs求子树和即可,最后,把每次的起点和终点都。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<ctime>
  7 #include<set>
  8 #include<map>
  9 #include<stack>
 10 #include<cstring>
 11 #define inf 2147483647
 12 #define For(i,a,b) for(register int i=a;i<=b;i++)
 13 #define p(a) putchar(a)
 14 #define g() getchar()
 15 //by war
 16 //2017.11.8
 17 using namespace std;
 18 int f[300010][20];
 19 int a[300010],b[300010];
 20 int deep[300010];
 21 int change[300010];
 22 bool vis[300010];
 23 int lca;
 24 int x,y;
 25 int n;
 26 struct node
 27 {
 28     int n;
 29     node *next;
 30 }*e[600010];
 31
 32 inline void in(register int &x)
 33 {
 34     int y=1;
 35     char c=g();x=0;
 36     while(c<‘0‘||c>‘9‘)
 37     {
 38     if(c==‘-‘)
 39     y=-1;
 40     c=g();
 41     }
 42     while(c<=‘9‘&&c>=‘0‘)x=(x<<1)+(x<<3)+c-‘0‘,c=g();
 43     x*=y;
 44 }
 45 inline void o(register int x)
 46 {
 47     if(x<0)
 48     {
 49         p(‘-‘);
 50         x=-x;
 51     }
 52     if(x>9)o(x/10);
 53     p(x%10+‘0‘);
 54 }
 55
 56 inline void push(register int x,register int y)
 57 {
 58     node *p;
 59     p=new node();
 60     p->n=y;
 61     if(e[x]==NULL)
 62     e[x]=p;
 63     else
 64     {
 65         p->next=e[x]->next;
 66         e[x]->next=p;
 67     }
 68 }
 69
 70 inline void build(register int now)
 71 {
 72     deep[now]=deep[f[now][0]]+1;
 73     for(register int i=1;(1<<i)<=n;i++)
 74     f[now][i]=f[f[now][i-1]][i-1];
 75     for(node *i=e[now];i!=NULL;i=i->next)
 76     {
 77         if(f[now][0]!=i->n)
 78         {
 79             f[i->n][0]=now;
 80             build(i->n);
 81         }
 82     }
 83 }
 84
 85 inline int query(register int x,register int y)
 86 {
 87     if(deep[x]<deep[y])
 88     swap(x,y);
 89     int c=deep[x]-deep[y];
 90     for(register int i=0;(1<<i)<=c;i++)
 91     if((1<<i)&c)
 92     x=f[x][i];
 93     if(x==y)
 94     return x;
 95     for(register int i=log2(deep[x]);i>=0;i--)
 96     {
 97         if(f[x][i]!=f[y][i])
 98         {
 99             x=f[x][i];
100             y=f[y][i];
101         }
102     }
103     return f[x][0];
104 }
105
106 int dfs(int now)
107 {
108     if(vis[now])
109     return b[now];
110     vis[now]=true;
111     for(node *i=e[now];i!=NULL;i=i->next)
112     if(!vis[i->n])
113     {
114     x=dfs(i->n);
115     b[now]+=x;
116     }
117     return b[now];
118 }
119
120 int main()
121 {
122 //    freopen("t.in","r",stdin);
123 //    freopen("t2.out","w",stdout);
124     in(n);
125     For(i,1,n)
126     in(a[i]);
127     For(i,1,n-1)
128     {
129         in(x),in(y);
130         push(x,y);
131         push(y,x);
132     }
133 //    f[0][0]=0;
134     build(1);
135     For(i,1,n-1)
136     {
137         x=a[i];
138         y=a[i+1];
139         lca=query(x,y);
140         change[x]++;
141         change[y]++;
142         change[lca]--;
143         change[f[lca][0]]--;
144     }
145     For(i,1,n)
146     b[i]=change[i];
147     b[1]=dfs(1);
148     For(i,2,n)
149     b[a[i]]--;
150     For(i,1,n)
151     o(b[i]),p(‘\n‘);
152      return 0;
153 }
时间: 2024-08-21 02:26:26

P3258 [JLOI2014]松鼠的新家的相关文章

【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家

[题目描述:] 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就

[Luogu] P3258 [JLOI2014]松鼠的新家

题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家.可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞.可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃. 维尼是个馋家伙,立马就答应了.现在松鼠希望知道为了保证维尼有

[JLOI2014]松鼠的新家 (树剖)

题目 P3258 [JLOI2014]松鼠的新家 解析 非常裸的一道树剖题 链上修改+单点查询的板子 记录一下所经过的点\(now[i]\),每次更新\(now[i-1]到now[i]\) 我们链上更新时上一次到的终点,是这一次一次更新的起点,又因为在\(a_n\)处可以不放糖,所以我们每次链上更新完成后,在这条链的终点位置处糖数\(-1\). 然后套板子直接做 代码 #include <bits/stdc++.h> using namespace std; const int N = 2e6

[填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 例题:[NOIP2015]运输计划 (然而我还没过就先不讲了) 反正就是中间有一步要求一条边被所有计划公共覆盖. 那么怎么求它呢?暴力(滚粗).我们有一个非常好的方法就是树上差分(记录tmp为差分数组) 询问操作为从叶子节点的权值向上累加到root 在一条路径u→ v,如果tmp[u]++,那么我

【BZOJ 3631】 [JLOI2014]松鼠的新家

3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 681 Solved: 329 [Submit][Status][Discuss] Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树"上.松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的

BZOJ 3631: [JLOI2014]松鼠的新家( 树链剖分 )

裸树链剖分... ------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int maxn = 300009; struct edge { int to; edge* next; } E[maxn << 1], *pit = E, *head[maxn]; inline void add(int u,

【Luogu P3258】[JLOI2014]松鼠的新家

Luogu P3258 题意就是对于一棵树,要求按照给出的顺序对每一个节点进行访问,记录每一个节点被经过的次数:特别地,我们认为只有从一个节点往外走才能被认为是经过一次.(最后一句话非常重要,仔细理解题意) 前置知识:树链剖分,差分. 最开始看到这道题我是打算使用树链剖分+线段树来做的. 但是我发现这个答案只需要每一个房间的糖果数--也就是说只需要区间修改+单点查询. 如果使用线段树的话,可能造成大量的空间浪费,而且常数也不小. 所以,我选择了使用树链剖分+差分进行统计. 由于差分写得比较少,本

题解 P3258 【[JLOI2014]松鼠的新家】

这道题可以说是树剖模板题...然而我一直WA10找不出错误...后来才发现是手抖打少了一个两个字符... 其实题目说的就是给你一颗树和一个遍历顺序,然后按照遍历顺序更新路径的值,最后查询所有节点的值. 其实这种题用树上差分会更理想,但是为了练树剖也就写了树剖. AC代码如下: 1097ms 56696kb #include<bits/stdc++.h> using namespace std; namespace StandardIO { template<typename T>i

BZOJ3631: [JLOI2014]松鼠的新家

传送门 树上的差分优化,很简单的一道题,应该属于NOIP2015TGD2T3的子问题. //BZOJ 3631 //by Cydiater //2016.10.25 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <ctime> #include <cstring> #include <string> #i