树链剖分//模板题
由于存在换根操作
对所有关于节点 u 的修改和查询操作进行分类讨论
若 Root 在 u 的子树中,则不处理 u 所在的 Root 的那颗子树
否则不会有影响
寻找 Root 所在的那颗子树的根可以用倍增求

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string> const int N = 1e5 + ; #define LL long long int topp[N], fa[N], size[N], son[N], deep[N], tree[N], lst[N], rst[N], bef[N], data[N];
int f[N][];
int Tree;
LL W[N << ], F[N << ], S[N << ];
struct Node {
int u, v, nxt;
} G[N << ];
int now, head[N];
int n, m, Root; int opt, T; #define gc getchar() inline int read() {
int x = ; char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' && c <= '') x = x * + c - '', c = gc;
return x;
} void Add(int u, int v) {G[++ now].v = v; G[now].nxt = head[u]; head[u] = now;} void Dfs_1(int u, int f_, int dep) {
fa[u] = f_, deep[u] = dep, size[u] = ;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v == f_) continue;
f[v][] = u;
Dfs_1(v, u, dep + );
size[u] += size[v];
if(size[son[u]] < size[v]) son[u] = v;
}
} void Dfs_2(int u, int tp) {
topp[u] = tp, tree[u] = ++ Tree, bef[Tree] = u, lst[u] = Tree;
if(!son[u]) {
rst[u] = Tree; return ;
}
Dfs_2(son[u], tp);
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u] && v != son[u]) Dfs_2(v, v);
}
rst[u] = Tree;
} void Before() {
for(int i = ; ( << i) <= n; i ++)
for(int j = ; j <= n; j ++)
if(f[j][i - ]) f[j][i] = f[f[j][i - ]][i - ];
} #define lson jd << 1
#define rson jd << 1 | 1 void Build_tree(int l, int r, int jd) {
S[jd] = (r - l + );
if(l == r) {
W[jd] = data[bef[l]];
return ;
}
int mid = (l + r) >> ;
Build_tree(l, mid, lson);
Build_tree(mid + , r, rson);
W[jd] = W[lson] + W[rson];
} void Pushdown(int jd) {
if(!F[jd]) return ;
F[lson] += F[jd];
F[rson] += F[jd];
W[lson] += (S[lson] * F[jd]);
W[rson] += (S[rson] * F[jd]);
F[jd] = ;
} void Sec_G(int l, int r, int jd, int x, int y, int num) {
if(x <= l && r <= y) {
F[jd] += num;
W[jd] += (S[jd] * num);
return ;
}
Pushdown(jd);
int mid = (l + r) >> ;
if(x <= mid) Sec_G(l, mid, lson, x, y, num);
if(y > mid) Sec_G(mid + , r, rson, x, y, num);
W[jd] = W[lson] + W[rson];
} void Sec_G_imp(int x, int y, int num) {
int tpx = topp[x], tpy = topp[y];
while(tpx != tpy) {
if(deep[tpx] < deep[tpy]) std:: swap(tpx, tpy), std:: swap(x, y);
Sec_G(, n, , tree[tpx], tree[x], num);
x = fa[tpx];
tpx = topp[x];
}
if(deep[x] < deep[y]) std:: swap(x, y);
Sec_G(, n, , tree[y], tree[x], num);
return ;
} inline int Find(int x, int y) {
int dy = deep[y], dx = deep[x];
int del = deep[y] - deep[x] - ;
for(int i = ; ( << i) <= del; i ++)
if(del & ( << i)) y = f[y][i];
return y;
} LL Answer; void Sec_A(int l, int r, int jd, int x, int y) {
if(x <= l && r <= y) {
Answer += W[jd];
return ;
}
Pushdown(jd);
int mid = (l + r) >> ;
if(x <= mid) Sec_A(l, mid, lson, x, y);
if(y > mid) Sec_A(mid + , r, rson, x, y);
} LL Sec_A_imp(int x, int y) {
int tpx = topp[x], tpy = topp[y];
LL ret = ;
while(tpx != tpy) {
if(deep[tpx] < deep[tpy]) std:: swap(tpx, tpy), std:: swap(x, y);
Answer = ;
Sec_A(, n, , tree[tpx], tree[x]);
ret += Answer;
x = fa[tpx];
tpx = topp[x];
}
if(deep[x] < deep[y]) std:: swap(x, y);
Answer = ;
Sec_A(, n, , tree[y], tree[x]);
ret += Answer;
return ret;
} int main() {
Root = ;
n = read();
for(int i = ; i <= n; i ++) head[i] = -;
for(int i = ; i <= n; i ++) data[i] = read();
for(int i = ; i < n; i ++) {
int u = read();
Add(i + , u), Add(u, i + );
}
Dfs_1(, , );
Dfs_2(, );
Build_tree(, n, );
Before();
int t = read();
for(T = ; T <= t; T ++) {
opt = read();
if(opt == ) Root = read();
else if(opt == ) {
int u = read(), v = read(), x = read();
Sec_G_imp(u, v, x);
} else if(opt == ) {
int u = read(), x = read();
if(Root == u) {
Sec_G(, n, , , n, x);
continue;
}
if(lst[u] <= tree[Root] && tree[Root] <= rst[u]) {
Sec_G(, n, , , n, x);
int Use_son = Find(u, Root);
Sec_G(, n, , lst[Use_son], rst[Use_son], -x);
} else Sec_G(, n, , lst[u], rst[u], x);
} else if(opt == ) {
int x = read(), y = read();
printf("%lld\n", Sec_A_imp(x, y));
} else {
int u = read();
if(Root == u) {
Answer = ;
Sec_A(, n, , , n);
printf("%lld\n", Answer);
continue;
}
LL Now_ans = ;
if(lst[u] <= tree[Root] && tree[Root] <= rst[u]) {
Answer = ;
Sec_A(, n, , , n);
Now_ans += Answer;
int Use_son = Find(u, Root);
Answer = ;
Sec_A(, n, , lst[Use_son], rst[Use_son]);
Now_ans -= Answer;
} else {
Answer = ;
Sec_A(, n, , lst[u], rst[u]);
Now_ans += Answer;
}
printf("%lld\n", Now_ans);
}
}
return ;
}

uoj #139的更多相关文章

  1. uoj #139. 【UER #4】被删除的黑白树 dfs序 贪心

    #139. [UER #4]被删除的黑白树 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/139 Descript ...

  2. 【uoj#139】[UER #4]被删除的黑白树 贪心

    题目描述 给出一个 $n$ 个节点的树,$1$ 号点为根.现要将其中一些点染成黑色,使得每个叶子节点(不包括根节点)到根节点路径上的黑点数相同.求最多能够染多少个黑点. 题解 贪心 显然有结论:选择的 ...

  3. ZJOI2019一轮停课刷题记录

    Preface 菜鸡HL终于狗来了他的省选停课,这次的时间很长,暂定停到一试结束,不过有机会二试的话还是可以搞到4月了 这段时间的学习就变得量大而且杂了,一般以刷薄弱的知识点和补一些新的奇怪技巧为主. ...

  4. 虚拟机上装uoj

    前期准备: x64 ubuntu 镜像.vmware.ss账号 注意一定要有64位镜像! ss不是必须的,不过没有的话就等着下载一晚上吧... 首先先装好ubuntu,我装的是ubuntu-16.04 ...

  5. 【UOJ #35】后缀排序 后缀数组模板

    http://uoj.ac/problem/35 以前做后缀数组的题直接粘模板...现在重新写一下模板 注意用来基数排序的数组一定要开到N. #include<cstdio> #inclu ...

  6. 【UOJ #246】【UER #7】套路

    http://uoj.ac/contest/35/problem/246 神奇!我这辈子是想不出这样的算法了. 对区间长度分类讨论:题解很好的~ 我已经弱到爆了,看完题解后还想了一晚上. 题解中&qu ...

  7. 【UOJ #244】【UER #7】短路

    http://uoj.ac/contest/35/problem/244 对其他人来说好简单的一道题,我当时却不会做TWT 注定滚粗啊 题解很好的~ #include<cstdio> #i ...

  8. 【BZOJ 3051】【UOJ #57】【WC 2013】平面图

    http://www.lydsy.com/JudgeOnline/problem.php?id=3051 http://uoj.ac/problem/57 这道题需要平面图转对偶图,点定位,最小生成树 ...

  9. 【UOJ #13】【UER #1】跳蚤OS

    http://uoj.ac/problem/13 建立trie树,然后建立go指针, 和AC自动机里的fail指针差不多, 走到一个快捷方式就从go指针走. 注意在trie树上要保留字符'/',不能用 ...

随机推荐

  1. go 数据渲染到html页面 02

    渲染到浏览器页面 //把数据渲染到浏览器 package main import ( "fmt" "text/template" "net/http& ...

  2. svn钩子(hooks)

    目录 钩子脚本的具体写法就是操作系统中shell脚本程序的写法,请根据自己SVN所在的操作系统和shell程序进行相应的写作 所谓钩子就是与一些版本库事件触发的程序,例如新修订版本的创建,或是未版本化 ...

  3. JAVA实现种子填充算法

    种子填充算法原理在网上很多地方都能找到,这篇是继上篇扫描线算法后另一种填充算法,直接上实现代码啦0.0 我的实现只是实现了种子填充算法,但是运行效率不快,如果大佬有改进方法,欢迎和我交流,谢谢! 最后 ...

  4. Springmvc的@ResponseBody方法返回Model时404:跳转jsp视图

    我有一个控制器方法,添加了@ResponseBody注解 @GetMapping(value = "/users") @ResponseBody public Map<Str ...

  5. 【已解决】老型号电脑需要按F1键才能进入系统

    [已解决]老型号电脑需要按F1键才能进入系统 本文作者:天析 作者邮箱:2200475850@qq.com 发布时间: Tue, 16 Jul 2019 20:49:00 +0800 问题描述:电脑因 ...

  6. S5PV210 时钟

    CLOCK DOMAINS 时钟域 S5PV210 consists of three clock domains, namely, main system (MSYS), display syste ...

  7. [原]Object-Oriented Programming With ANSI-C

    前一段时间面试被问到一个问题,怎么用C去实现面向对象的特性,比如封装.继承和多态.我心想这不是闲的蛋疼么,好吧,我承认我不会...[大哭].然后去网上找相关的文章,有文章推荐了<Object-O ...

  8. redis windows安装与liunx安装

    windows安装redis 2.把安装包放在Linux文件系统下,利用WinSCP工具 3.解压缩 tar -zxf redis-4.0.2.tar.gz 4.切换到解压后的目录 cd redis- ...

  9. kubernetes Node节点部署(四)

    一.部署kubelet 1.1.二进制包准备 将软件包从linux-node1复制到linux-node2中去 [root@linux-node1 ~]# cd /usr/local/src/kube ...

  10. Java锁--CyclicBarrier

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3533995.html CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一 ...