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. 电信光猫带路由器(F452)的虚拟服务器端口映射

    现在电信宽带的光猫一般都自带路由器功能,为了方便运营商管理网络用户,电信公司插入了企业局域网,网络用户的光猫路由器都是这个局域网的节点.用户家里的电脑在网络中的结构位置一般如下所示: 互联网(公网)= ...

  2. react开发中的小细节

    目前开始使用react余遇到的问题还不是很多,但还是希望总结一下. react中的属性prop: 在react中组件的父子组件的通信是基于prop的,当然对于底层的东西不是特别了解,但可以说一说它的基 ...

  3. H3C软件开发笔试面试总结

    注:我目前是陕西师范大学计算机科学学院本科生,在西安参加笔试以及面试 先是笔试,我选择的是JAVA方向,笔试选择题目主要是一些基础性的题目,然后简答题问了final.finally.finallize ...

  4. ASP.NET Core on K8S深入学习(3)Deployment

    上一篇<部署过程解析与安装Dashboard>中我们了解K8S的部署过程,这一篇我们来了解一下K8S为我们提供的几种应用运行方式:Deployment.DaemonSet与Job,它们是K ...

  5. python异常处理-异常捕获-抛出异常-断言-自定义异常-UDP通信-socketserver模块应用-3

    异常捕获 异常:程序在运行过程中出现了不可预知的错误,并且该错误没有对应的处理机制,那么就会以异常的形式表现出来 影响:整个程序无法再正常运行 异常的结构 异常的类型 NameError 异常的信息 ...

  6. @Value注解 和 @Data注解

    @Value注解 service层代码 @Service public class HelloServiceImpl implements HelloService { @Autowired priv ...

  7. CSS:抗锯齿 font-smoothing

    本文引自:http://www.cnblogs.com/sunshq/p/4595673.html -webkit-font-smoothing 这个属性可以使页面上的字体抗锯齿,使用后字体看起来会更 ...

  8. 分享我的GD32F450的IAP过程

    最近一个项目使用GD32F450VI+ESP8266需要做远程升级,基本参考正点原子IAP的那一章节,但是在GD32F450上却遇到了问题,无法跳转,然后使用正点原子的开发板stm32f429,以及s ...

  9. DT-06 For Homekit

    一. 配置DT-06上网 连接此热点,会自动弹出wifi配置页面. 输入选中的路由密码,点 Join加入,如果路由没有出现在列表中,点 Other手工输入(仅支持2.4g路由配置) 二.配置dt-06 ...

  10. 解决树莓派烧录系统后没有boot文件,只出现盘符问题

    首先,如果下图情况,说明你没有烧录好,继续向下看 放一张安装成功的图片 出现这个的原因是因为前期没有烧录好,它会回滚到img文件中,如果中途退出,它会写入到img文件中 正确文件大小(Raspbian ...