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应用无法下载、此时无法安装应用程序

    无法安装应用 app开发者,进行程序测试,重试还不行,就重新打包, 个人,更改wifi的dns 在“设置” –> “WiFi” –> 进入当前的WiFi 进入之后点击旁边的叹号,然后进入之 ...

  2. poj 3714 寻找最近点对

    参考自<编程之美>169页,大概原理就是把区间分成两部分,然后递归找每一部分中最近的点对,还有一种情况就是这个点对分属于这两部分,然后选两部分中的部分点枚举即可,取其最小值. //2013 ...

  3. 用机智云做PWM占空比控制电机,物联网智能家居应用

      因为是新申请的博客,所以申请了总想往里面加点东西,所以把我之前在机智云写的帖子复制了过来 (各位抱歉,由于之前上传的文件可能有错误,之前上传的文件PWM不能用,那么我又重新上传了一个文件,这个文件 ...

  4. windows下hexo+github搭建个人博客

    网上利用hexo搭建博客的教程非常多,大部分内容都大同小异,选择一篇合适的参考,跟着一步一步来即可. 但是,很多博客由于发布时间较为久远等问题,其中某些操作在现在已不再适用,从而导致类似于我这样的小白 ...

  5. JWT详解

    目录 1.前言 2.JWT的数据结构 2.1 Header 2.2 Payload 2.3 Signature 2.4 Base64URL 3. JWT的实现   1.前言 定义:JSON Web T ...

  6. 8.源码分析---从设计模式中看SOFARPC中的EventBus?

    我们在前面分析客户端引用的时候会看到如下这段代码: // 产生开始调用事件 if (EventBus.isEnable(ClientStartInvokeEvent.class)) { EventBu ...

  7. GBK和UTF-8的区别

    我们这里将以最简单最容易理解的方式来描述GBK和UTF8的区别,以及它们分别是什么.   GBK编码:是指中国的中文字符,其它它包含了简体中文与繁体中文字符,另外还有一种字符“gb2312”,这种字符 ...

  8. 同“窗”的较量:部署在 Windows 上的 .NET Core 版博客站点发布上线

    为了验证 docker swarm 在高并发下的性能问题,周一我们发布了使用 docker-compose 部署的 .net core 版博客站点(博文链接),但由于有1行代码请求后端 web api ...

  9. python第一课--基础知识

    python简介 Python是一种计算机程序设计语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的.大型项目的 ...

  10. vue过滤器微信小程序过滤器和百度智能小程序过滤器

    因为最近写了微信小程序和百度小程序,用到了过滤器,感觉还挺好用的,所以就来总结一下,希望能帮到你们. 1. 微信小程序过滤器: 1.1:首先建一个单独的wxs后缀的文件,一般放在utils文件夹里面. ...