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, int v) {

pit->to = v;

pit->next = head[u];

head[u] = pit++;

}

#define addedge(u, v) add(u, v), add(v, u)

#define M(l, r) (((l) + (r)) >> 1)

int dep[maxn], size[maxn], son[maxn], fa[maxn], top[maxn], id[maxn], TOP, CK = 0;

void dfs(int x) {

son[x] = -(size[x] = 1);

for(edge* e = head[x]; e; e = e->next) if(e->to != fa[x]) {

dep[e->to] = dep[x] + 1;

fa[e->to] = x;

dfs(e->to);

size[x] += size[e->to];

if(!~son[x] || size[son[x]] < size[e->to])

son[x] = e->to;

}

}

void DFS(int x) {

top[x] = TOP;

id[x] = ++CK;

if(~son[x]) DFS(son[x]);

for(edge* e = head[x]; e; e = e->next)

if(e->to != son[x] && e->to != fa[x]) DFS(TOP = e->to);

}

void init() {

dfs(dep[0] = 0);

DFS(TOP = 0);

}

struct Node {

Node *l, *r;

int add;

Node():add(0) {}

} pool[maxn * 20], *pt = pool, *root;

void build(Node* t, int l, int r) {

if(r > l) {

int m = M(l, r);

build(t->l = pt++, l, m);

build(t->r = pt++, m + 1, r);

}

}

int L, R, N;

void modify(Node* t, int l, int r) {

if(L <= l && r <= R)

t->add++;

else {

int m = M(l, r);

if(L <= m) modify(t->l, l, m);

if(m < R) modify(t->r, m + 1, r);

}

}

int query(Node* t, int l, int r) {

R += t->add;

if(l == r)

return R;

int m = M(l, r);

return L <= m ? query(t->l, l, m) : query(t->r, m + 1, r);

}

void change(int x, int y) {

for(; top[x] != top[y]; x = fa[top[x]]) {

if(dep[top[x]] < dep[top[y]]) swap(x, y);

L = id[top[x]]; R = id[x];

modify(root, 1, N);

}

if(dep[x] < dep[y]) swap(x, y);

L = id[y]; R = id[x];

modify(root, 1, N);

}

int path[maxn];

int main() {

cin >> N;

for(int i = 0; i < N; i++)

scanf("%d", path + i), path[i]--;

for(int i = 0; i < N - 1; i++) {

int u, v; scanf("%d%d", &u, &v); --u; --v;

addedge(u, v);

}

init();

build(root = pt++, 1, N);

for(int i = 1; i < N; i++)

change(path[i - 1], path[i]);

for(int i = 0; i < N; i++) {

L = id[i]; R = 0;

int t = query(root, 1, N);

if(i != path[0]) t--;

printf("%d\n", t);

}

return 0;

}

-------------------------------------------------------------------

3631: [JLOI2014]松鼠的新家

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 855  Solved: 412
[Submit][Status][Discuss]

Description

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。

可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。维尼是个馋家伙,立马就答应了。

现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

Input

第一行一个整数n,表示房间个数

第二行n个整数,依次描述a1-an

接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

Output

一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。

Sample Input

5
1 4 5 3 2
1 2
2 4
2 3
4 5

Sample Output

1
2
1
2
1

HINT

2<= n <=300000

Source

时间: 2024-10-16 22:27:39

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

BZOJ 3631 JLOI2014 松鼠的新家 树链剖分/LCA

题目大意:给定一棵无根树和一个序列,在这个序列上依次遍历,求每个点的访问次数(最后一个点的访问次数要-1) 树链剖分的裸题--考场上我还是一个弱渣,啥也不会,暴力得了50分,剩下两道题爆零了...而且30W深搜爆栈,人生第一次手写了系统栈.. 回来因为这题的原因去学了树链剖分 结果没学明白 每条重链单独开了一棵线段树 常数大的要死 高一时写的代码...还是别看了,拿去对拍可以,阅读性欠佳 #include<stdio.h> #include<stdlib.h> #include&l

[JLOI2014]松鼠的新家-树链剖分

最开始的时候我在写线段树部分的时候还打了一个build,后来一想,打个球球大作战的build啊!!!有个锤子的用啊!!! 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3e6+5; 4 int n; 5 int e,begin[maxn],next[maxn],to[maxn],a[maxn]; 6 int tree[maxn<<2],lazy[maxn<<2]; 7 int so

BZOJ3631: [JLOI2014]松鼠的新家 树链剖分/lca/树上查分

求n次lca后树上差分. 每次移动时在起始点和终点各打一个start标记,在LCA和LCA的父节点处各上打一个end标记,然后深搜,start标记一直上传,遇到end标记就停止,最后再处理一下就行 % PoPoQQQ大爷 #include<bits/stdc++.h> #define rep(i,l,r) for(int i=l;i<=r;i++) #define N 310000 using namespace std; int head[N],dep[N],sz[N],son[N],

BZOJ3631 松鼠的新家(树链剖分)

题目链接 松鼠的新家 差不多可以说是树链剖分的模板题了,直接维护即可. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 7 #define dec(i,a,b) for(int i(a); i >= (b); --i) 8 #

BZOJ 3631 [JLOI2014]松鼠的新家 | 树上差分

链接 BZOJ 3631 题解 看起来是树剖?实际上树上差分就可以解决-- 当要给一条路径(u, v) +1的时候,给d[u] += 1, d[v] += 1, d[lca(u, v)] -= 1, d[fa[lca(u, v)]] -= 1. 注意这道题中路径的终点是不 +1的. #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <q

BZOJ 3631 [JLOI2014]松鼠的新家

题解:树上差分就可以了 论看懂题意的重要性 最后-1的时候处理错了,WA了几发 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=600009; const int Inf=1000000000; int n,m; int a[maxn]; int cntedge; int head[maxn]; int to[maxn<<1],

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

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

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

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

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

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