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. 【iOS】获取视图的中心和宽高

    示例代码: NSLog(@"%f, %f", self.view.center.x, self.view.center.y); NSLog(@"%f, %f", ...

  2. 在 alpine 中使用 NPOI

    在 alpine 中使用 NPOI Intro 在 .net 中常使用 NPOI 来做 Excel 的导入导出,NPOI 从 2.4.0 版本开始支持 .netstandard2.0,对于.net c ...

  3. ansible批量管理服务 上

    1 ansible简介 1.1 ansible批量管理服务概述 (1)是基于python语言开发的自动化软件工具(2)是基于SSH远程管理服务实现远程主机批量管理(3)并行管理,部署简单,应用也简单方 ...

  4. 如何在MySQL中输入中文

    解决MySQL中的Incorrect string value MySQL中输入中文:在MySQL建标的时候,直接往表中的varchar(255)中输入中文的话是会报错的,大概是因为数据库的默认编码是 ...

  5. c#小灶——标识符和关键字

    标识符 我们之前说,命名空间的名字是自己取的,类名也是自己取的,方法名也是自己取的,以后还有各种常量.变量.对象……这些名字是自己取的.这些名字,就是标识符. 标识符规则: 标识符可以包含大小写字母. ...

  6. PythonDay03

    ## 第三章 ### 今日内容 1.整型 2.布尔值 3.字符串 ​ 索引​ 切片​ 步长​ 字符串的方法 4.for循环 ### 1.整型 - python3:全部是整形- python2:整形,长 ...

  7. linux环境下搭建自动化Jenkins管理工具

    一.搭建一个jak--tomcat服务器到自己的linux服务器上 具体的服务器搭建这里可以参考华华大佬的博客:https://www.cnblogs.com/liulinghua90/p/46614 ...

  8. python3学习-pickle模块

    pickle提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上. 基本接口: pickle.dump(obj, file, [,protocol]) 注解:将对象obj保存到文件file中 ...

  9. WebService—— IDEA创建WebServices

    一.File–>New–>Project 弹出这个对话框后,照下图的勾选然后点击Next,然后填写项目名和项目路径后,点击finish. 二.生成目录如下 需要注意的有HelloWorld ...

  10. JavaWeb——Servlet开发3

    1.使用初始化参数配置应用程序 初始化参数的方式有两种 在Web.xml文件中使用<context-param>标签声明上下文初始化参数 <context-param> < ...