BZOJ4381 : [POI2015]Odwiedziny / Luogu3591[POI2015]ODW - 分块+树剖
Solution
在步伐$pace$比较小的时候, 我们发现用前缀和直接维护会很快
而在$pace$比较大的时候, 则暴力往上跳会最优
设$blo= \sqrt{N}$
若$pace<=blo$, 则利用前缀和更新,
预处理复杂度$O(N \sqrt{N})$, 查询复杂度$O(1)$
若$pace>blo$,则利用树剖逐渐往上跳
总共要跳$N/pace$次, 一共有$logN$条轻重链, 复杂度为$O(logN+ \sqrt{N})$
代码实现比较麻烦, 我常数写的还很差, 水平低啊QAQ
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rd read()
#define N 50005
#define M 240
#define R register
using namespace std; int n, blo, a[N], b[N], f[N][M], sum[N][M];
int fa[N], dep[N], top[N], sz[N], son[N], id[N], idf[N], cnt;
int head[N], tot; struct edge {
int nxt, to;
}e[N << ]; inline char nc(){
static char buf[], *p1=buf, *p2=buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, , , stdin), p1 == p2) ? EOF : *p1++;
}
inline int read(){
char ch = nc();int sum = ;
while(!(ch >= '' && ch <= '')) ch = nc();
while(ch >= '' && ch <= '') sum = sum * + ch - , ch = nc();
return sum;
} inline void add(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
} inline void sw(int &A, int &B) {
A ^= B; B ^= A; A ^= B;
} inline void dfs1(R int u) {
sz[u] = ;
for (R int i = head[u]; i; i = e[i].nxt) {
R int nt = e[i].to;
if (nt == fa[u]) continue;
f[nt][] = fa[nt] = u;
dep[nt] = dep[u] + ;
dfs1(nt);
sz[u] += sz[nt];
if (sz[nt] > sz[son[u]])
son[u] = nt;
}
} inline void dfs2(R int u) {
idf[id[u] = ++cnt] = u;
if (!son[u]) return;
top[son[u]] = top[u];
dfs2(son[u]);
for (R int i = head[u]; i; i = e[i].nxt) {
R int nt = e[i].to;
if (nt == fa[u] || nt == son[u]) continue;
top[nt] = nt;
dfs2(nt);
}
} inline int LCA(R int x, R int y) {
for (;top[x] != top[y]; ) {
if (dep[top[x]] < dep[top[y]]) sw(x, y);
x = fa[top[x]];
}
if (dep[x] < dep[y]) sw(x, y);
return y;
} inline int work1(R int x, R int y, R int pace) {
R int lca = LCA(x, y), len = dep[x] + dep[y] - * dep[lca], res = ;
if (len % pace) {
res += a[y];
y = f[y][len % pace];
len -= len % pace;
}
len = dep[x] - dep[lca];
if (len % pace == ) {
res += sum[x][pace] - sum[lca][pace];
res += sum[y][pace] - sum[lca][pace];
res += a[lca];
return res;
}
R int tmp = f[lca][pace - len % pace];
res += sum[x][pace] - sum[tmp][pace];
if (dep[y] < dep[lca]) return res;
len = dep[y] - dep[lca];
tmp = f[lca][pace - len % pace];
res += sum[y][pace] - sum[tmp][pace];
return res;
} inline int up(R int x, R int d) {
R int y = top[x];
for (; x && dep[x] - dep[y] < d;) {
d -= dep[x] - dep[y] + ;
x = fa[top[x]];
y = top[x];
}
if (!x) return ;
return idf[id[x] - d];
} inline int work2(R int x, R int y, R int pace) {
R int lca = LCA(x, y), len = dep[x] + dep[y] - * dep[lca], res = ;
if (len % pace) {
res += a[y];
y = up(y, len % pace);
len -= len % pace;
}
len = dep[x] - dep[lca];
if (len % pace == ) {
while (x && dep[x] > dep[lca])
res += a[x], x = up(x, pace);
while (y && dep[y] > dep[lca])
res += a[y], y = up(y, pace);
res += a[lca];
return res;
}
while (x && dep[x] > dep[lca])
res += a[x], x = up(x, pace);
while (y && dep[y] > dep[lca])
res += a[y], y = up(y, pace);
return res;
} int main()
{
n = rd; blo = sqrt(n);
for (R int i = ; i <= n; ++i)
a[i] = rd;
for (R int i = ; i < n; ++i) {
int u = rd, v = rd;
add(u, v); add(v, u);
}
dep[] = ; dfs1();
top[] = ; dfs2();
for (R int j = ; j <= blo; ++j)
for (R int i = ; i <= n; ++i)
f[i][j] = f[f[i][j - ]][];
for (R int j = ; j <= blo; ++j)
for (R int i = ; i <= n; ++i)
sum[i][j] = a[i];
for (R int j = ; j <= blo; ++j)
for (R int i = ; i <= n; ++i) {
int x = idf[i];
sum[x][j] += sum[f[x][j]][j];
}
for (R int i = ; i <= n; ++i) b[i] = rd;
for (R int i = ; i < n; ++i) {
R int x = rd;
if (x <= blo) printf("%d\n", work1(b[i], b[i + ], x));
else printf("%d\n", work2(b[i], b[i + ], x));
}
}
BZOJ4381 : [POI2015]Odwiedziny / Luogu3591[POI2015]ODW - 分块+树剖的更多相关文章
- HDU5840 Problem This world need more Zhu 分块 树剖
给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1,求树链上所有点的新编号cnt满足cnt%k==0的点的权值的最大值.n,m, ...
- [POI2015]Odwiedziny
[POI2015]Odwiedziny 题目大意: 一棵\(n(n\le5\times10^4)\)个点的树,\(n\)次询问从一个点到另一个点的路径上,每次跳\(k\)个点,所经过的点权和. 思路: ...
- 【BZOJ 3295】动态逆序对 - 分块+树状数组
题目描述 给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数. 分析:分块+树状数组 (PS:本题的CDQ分治解法见下一篇) 首先将序列分成T块,每一块开一个树状数组,并且先把最初的 ...
- 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)
4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...
- 【UOJ#435】【集训队作业2018】Simple Tree 分块+树链剖分
题目大意: 有一棵有根树,根为 1 ,点有点权.现在有 m 次操作,操作有 3 种:1 x y w ,将 x 到 y 的路径上的点点权加上 w (其中 w=±1w=±1 ):2 x y ,询问在 x ...
- 【bzoj2141】排队 分块+树状数组
题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别, ...
- 【bzoj3744】Gty的妹子序列 分块+树状数组+主席树
题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成 ...
- 【分块+树状数组】codechef November Challenge 2014 .Chef and Churu
https://www.codechef.com/problems/FNCS [题意] [思路] 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数 查询时求前缀和,对于 ...
- BZOJ 4765(分块+树状数组)
题面 传送门 "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能计算数列区间和,而普通计算姬能计算树中子树和.更 ...
随机推荐
- 解压zipfile & tarfile
def __un_zip(self, file_path): """解压.zip格式文件到同名目录下,若解压之前就存在该目录说明已解压,跳过解压过程,返回该目录" ...
- Azure VMSS (3) 修改VM Template并创建VMSS
<Windows Azure Platform 系列文章目录> 在开始本章内容之前,我们需要准备好Azure VM的镜像,具体可以参考:Azure VMSS (2) 对VM执行Genera ...
- 彻底放弃没落的MFC,对新人的忠告!--吃瓜群众围观撕逼
http://bbs.csdn.net/topics/391817496 完全没想到10多年后还有人纠结要不要学MFC,我花点时间给新人们一个总结. 第1种观点 学习完MFC,你会更理解编程的思想,再 ...
- DokuWiki 命名空间管理
为了更好的组织结构,Dokuwiki提供了命名空间这个功能,那怎么管理命名空间的,其实可以安装插件去管理 Add New Page Plugin:新建界面 https://www.dokuwiki.o ...
- linux git 保存用户名和密码
一.通过文件方式 1.在~/下, touch创建文件 .git-credentials, 用vim编辑此文件,输入内容格式: touch .git-credentials vim .git-crede ...
- 大数据的乘法实现——C语言
1大数据乘法的算法思路: 输入两个字符串,得到结果,例如:123456789*123456789: 思路:1)首先 123456789*1 = 9 18 27 36 45 54 63 ...
- vue+窗格切换+田字+dicom显示_01
环境:vue+webpack+cornerstone ide:vs code 需求:窗格设置+拼图设置 1.点击左边第一个窗格或者默认显示. 2.点击第二个也同理显示,以此类推 3.选择左边的窗格之后 ...
- maven的依赖管理详细
依赖管理 Jar包的管理 需求:整合struts2 页面上传一个客户id 跳转页面 1 添加依赖: 打开maven仓库的视图: 2 重建索引 1. 创建maven项目(同上) 2. 跳过骨架(同上 ...
- BASIC GIT WORKFLOW
BASIC GIT WORKFLOW Generalizations You have now been introduced to the fundamental Git workflow. You ...
- mysql_config_editor usage
# mysql_config_eidtor is a tool to create a profile file $HOME/.mylogin.cnf, in which you can store ...