Tree

题意: 给你一颗树, 每一个节点都有一个权值, 如果一个石头落在某个节点上, 他就会往上跳这个的点的权值步。 现在有2种操作, 1 把一个石头放在 x 的位置 询问有跳几次才跳出这棵树, 2 修改某个节点的权值。

解法:树上分块, 用dfs分好块之后。 对于每一块都处理出如果石头落在某个位置之后他跳出这个块之后的位置和次数。

每次更新都自己这一块的所有子节点, 然后找第k个父亲的时候用倍增优化。

对于每次询问都跳到0号点之后,返回所经过的次数。

我们可以对属于同一块内的节点重新建立边, 因为我们在更新的时候不会直接访问到别的块的点, 所以重新建立边,避免遍历不需要的边(快了200ms)。

代码:

 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int n, m, b;
int head[N], to[N], nt[N]; /// E1
int head2[N], to2[N], nt2[N]; /// E2
int Stack[N], belong[N];
int jump[N], tto[N], cnt[N];
int tot, top, type, tot2;
int anc[N][];
inline void add2(int u, int v){
to2[tot2] = v;
nt2[tot2] = head2[u];
head2[u] = tot2++;
}
inline void add(int u, int v){
to[tot] = v;
nt[tot] = head[u];
head[u] = tot++;
}
void dfs(int u){
int now = top, v;
for(int i = head[u]; ~i; i = nt[i]){
v = to[i];
anc[v][] = u;
for(int i = ; i < ; i++)
anc[v][i] = anc[anc[v][i-]][i-];
dfs(v);
if(top-now >= b){
++type;
while(top!=now){
belong[Stack[top--]] = type;
}
}
}
Stack[++top] = u;
}
inline int Find(int x, int k){
for(int i = ; i >= ; i--)
if((k>>i)&) x = anc[x][i];
return x;
}
inline void Update(int x){
int z = jump[x];
if(belong[z] == belong[x]){
tto[x] = tto[z];
cnt[x] = cnt[z] + ;
}
else {
tto[x] = z;
cnt[x] = ;
}
}
void Build(int x){
Update(x);
for(int i = head[x]; ~i; i = nt[i])
Build(to[i]);
}
inline int solve(int p){
int ret = ;
while(p){
ret += cnt[p];
p = tto[p];
}
return ret;
}
void dUpdate(int x){
Update(x);
for(int i = head2[x]; ~i; i = nt2[i]){
dUpdate(to2[i]);
}
}
void dfs2(int x){
for(int i = head[x]; ~i; i = nt[i]){
if(belong[x] == belong[to[i]]){
add2(x, to[i]);
}
dfs2(to[i]);
}
}
int main(){
int t, x;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
b = sqrt(n);
tot = ;top = ; type = ;tot2 = ;
memset(head, -, sizeof(int)*(n+));
memset(head2, -, sizeof(int)*(n+));
for(int i = ; i <= n; i++){
scanf("%d", &x);
add(x, i);
}
dfs();
while(top) belong[Stack[top--]] = type;
dfs2();
for(int i = ; i <= n; i++){
scanf("%d", &x);
jump[i] = Find(i, x);
}
Build();
scanf("%d", &m);
int op, k;
while(m--){
scanf("%d", &op);
if(op == ) {
scanf("%d", &x);
printf("%d\n", solve(x));
}
else {
scanf("%d%d", &x, &k);
jump[x] = Find(x, k);
dUpdate(x);
}
}
}
return ;
}

还有1种lct的写法,和弹飞绵羊的写法差不多,唯一有区别的就是找落地点在哪里,直接套lct的板子就好了,再用倍增找下一次去的位置就好了。

代码:

 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch tr[x].son[0]
#define rch tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int n, m, b;
int head[N], to[N], nt[N];
int tot, top, type, tot2;
int anc[N][];
inline void add(int u, int v){
to[tot] = v;
nt[tot] = head[u];
head[u] = tot++;
}
void dfs(int u){
int now = top, v;
for(int i = head[u]; ~i; i = nt[i]){
v = to[i];
anc[v][] = u;
for(int i = ; i < ; i++)
anc[v][i] = anc[anc[v][i-]][i-];
dfs(v);
}
}
inline int Find(int x, int k){
for(int i = ; i >= ; i--)
if((k>>i)&) x = anc[x][i];
return x;
}
struct Node{
int son[], pre;
int sz, is_root;
inline void init() {
son[] = son[] = pre = ;
sz = is_root =;
}
}tr[N];
void Push_Up(int x){
if(!x) return ;
tr[x].sz = tr[lch].sz + tr[rch].sz + ;
}
void rotate(int x){
if(tr[x].is_root) return ;
int y = tr[x].pre, z = tr[y].pre;
int k = x == tr[y].son[];
tr[y].son[k] = tr[x].son[k^];
tr[tr[y].son[k]].pre = y;
tr[x].son[k^] = y;
tr[y].pre = x;
tr[x].pre = z;
if(tr[y].is_root) tr[x].is_root = , tr[y].is_root = ;
else tr[z].son[ tr[z].son[] == y] = x;
Push_Up(y); }
void Splay(int x){
while(!tr[x].is_root){
int y = tr[x].pre, z = tr[y].pre;
if(!tr[y].is_root){
if((y == tr[z].son[]) != ( x == tr[y].son[])) rotate(y);
else rotate(x);
}
rotate(x);
}
Push_Up(x);
}
void access(int x){
int y = ;
do{
Splay(x);
tr[rch].is_root = ;
rch = y;
tr[rch].is_root = ;
Push_Up(x);
y = x;
x = tr[x].pre;
}while(x);
}
inline void link(int u, int v){
if(v > n) v = ;
tr[u].pre = v;
}
inline void cut(int x){
access(x);
Splay(x);
tr[lch].is_root = ;
tr[lch].pre = ;
lch = ;
Push_Up(x);
}
inline int Query(int x){
access(x);
Splay(x);
return tr[lch].sz + ;
}
int main(){
int t, x;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
tot = ;
memset(head, -, sizeof(int)*(n+));
tr[].init();
for(int i = ; i <= n; i++){
tr[i].init();
scanf("%d", &x);
add(x, i);
}
dfs();
for(int i = ; i <= n; i++){
scanf("%d", &x);
link(i, Find(i,x));
}
scanf("%d", &m);
int op, k;
while(m--){
scanf("%d", &op);
if(op == ) {
scanf("%d", &x);
printf("%d\n", Query(x));
}
else {
scanf("%d%d", &x, &k);
cut(x);
link(x, Find(x,k));
}
}
}
return ;
}

虽然dls说分块和lct复杂度差不多, 但是这2份代码相比较lct快了100多, 实际上我觉得树上分块比较玄学。

HDU 6394 Tree 分块 || lct的更多相关文章

  1. HDU - 6394 Tree(树分块+倍增)

    http://acm.hdu.edu.cn/showproblem.php?pid=6394 题意 给出一棵树,然后每个节点有一个权值,代表这个点可以往上面跳多远,问最少需要多少次可以跳出这颗树 分析 ...

  2. hdu 6394 Tree (2018 Multi-University Training Contest 7 1009) (树分块+倍增)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=6394 思路:用dfs序处理下树,在用分块,我们只需要维护当前这个点要跳出这个块需要的步数和他跳出这个块去 ...

  3. hdu 5398 动态树LCT

    GCD Tree Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Su ...

  4. hdu 5002 (动态树lct)

    Tree Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  5. hdu 5909 Tree Cutting [树形DP fwt]

    hdu 5909 Tree Cutting 题意:一颗无根树,每个点有权值,连通子树的权值为异或和,求异或和为[0,m)的方案数 \(f[i][j]\)表示子树i中经过i的连通子树异或和为j的方案数 ...

  6. HDU 5044 Tree(树链剖分)

    HDU 5044 Tree field=problem&key=2014+ACM%2FICPC+Asia+Regional+Shanghai+Online&source=1&s ...

  7. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  8. HDU 5002 Tree(动态树LCT)(2014 ACM/ICPC Asia Regional Anshan Online)

    Problem Description You are given a tree with N nodes which are numbered by integers 1..N. Each node ...

  9. HDU 5002 Tree LCT 区间更新

    Tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.action?c ...

随机推荐

  1. CSS开启硬件加速来提高网站性能

    原文永久链接 CSS animations, transforms 以及 transitions 不会自动开启GPU加速,而是由浏览器的缓慢的软件渲染引擎来执行. 那我们怎样才可以切换到GPU模式呢, ...

  2. Zabbix-agentd错误整理

    一.无法启动 (一).当时环境 Firewalld与Selinux,Iptables都为关闭 配置环境 OS:CentOS Zabbix-server IP:10.18.43.71 Hostname: ...

  3. 【Java笔记】【Java核心技术卷1】chapter3 D3数据类型

    package chapter3; public class D3数据类型 { public static void main(String[] arg) { //Java 整型(字节数不会随硬件变化 ...

  4. Apache 80端口可以访问,8080却不可访问

    RT, 记录一下,后面看是否有解决方案.

  5. Nginx编译安装模块(非重装)

    假如原已经安装好的Nginx,现在需要添加一个未被编译安装的ssl模块,我们该怎么办呢?重装,还是有其他的办法?当然不需要重装的,下面我们看下如何实现的. 1.cd到Nginx解压过后的目录[root ...

  6. intellij idea与github整合管理代码

    各位看官大家好,博主每每在公司学习新知识写代码时都需要通过U盘带回家来继续每天的学习,觉得这样实在麻烦,于是今天就整合了一下github来完成代码的管理. 开始之前我们需要准备三样东西:1.intel ...

  7. STL 队列

    头文件 #include <queue> 定义 普通队列: queue < int > q; 优先队列: priority_queue < int, vector< ...

  8. ABP 配置全局数据过滤器 II

    第一篇 那种写法有些复杂, 简单办法是直接注入 切换到 ***.EntityFramework 项目 在Uow 里面创建 ***EfUnitOfWork.cs 类 public class Coope ...

  9. .NET Core下操作Git,自动提交代码到 GitHub

    .NET Core 3.0 预览版发布已经好些时日了,博客园也已将其用于生产环境中,可见 .NET Core 日趋成熟 回归正题,你想盖大楼吗?想 GitHub 首页一片绿吗?今天拿她玩玩自动化提交代 ...

  10. net必问的面试题系列之基本概念和语法

    上个月离职了,这几天整理了一些常见的面试题,整理成一个系列给大家分享一下,机会是给有准备的人,面试造火箭,工作拧螺丝,不慌,共勉. 1.net必问的面试题系列之基本概念和语法 2.net必问的面试题系 ...