[POI2015]Odwiedziny
[POI2015]Odwiedziny
题目大意:
一棵\(n(n\le5\times10^4)\)个点的树,\(n\)次询问从一个点到另一个点的路径上,每次跳\(k\)个点,所经过的点权和。
思路:
分块思想。
当\(k\ge\sqrt n\)时,显然每次询问不会跳超过\(\sqrt n\)次,可以借助树链剖分在\(\mathcal O(\sqrt n)\)的时间内暴力完成询问。
当\(k<\sqrt n\)时,预处理从一个点出发,每次跳\(k\)格,跳到根结点的权值和。可以\(\mathcal O(\log n)\)求LCA,\(\mathcal O(1)\)回答。
时间复杂度\(\mathcal O(n\sqrt n)\)。
源代码:
#include<cmath>
#include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=50001,B=223;
int n,block,a[N],b[N],c[N];
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
int anc[N][B],sum[N][B],dep[N],top[N],son[N],size[N],dfn[N],id[N];
void dfs(const int &x,const int &par) {
size[x]=1;
anc[x][1]=par;
sum[x][1]=sum[par][1]+a[x];
dep[x]=dep[par]+1;
for(register int i=2;i<block;i++) {
anc[x][i]=anc[anc[x][i-1]][1];
sum[x][i]=sum[anc[x][i]][i]+a[x];
}
for(unsigned i=0;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]]) {
son[x]=y;
}
}
}
void dfs(const int &x) {
dfn[x]=++dfn[0];
id[dfn[x]]=x;
top[x]=x==son[anc[x][1]]?top[anc[x][1]]:x;
if(son[x]) dfs(son[x]);
for(unsigned i=0;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==anc[x][1]||y==son[x]) continue;
dfs(y);
}
}
inline int lca(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
x=anc[top[x]][1];
}
if(dep[x]<dep[y]) std::swap(x,y);
return y;
}
inline int father(int x,int k) {
if(k>=dep[x]) return 0;
while(k>=dep[x]-dep[top[x]]+1) {
k-=dep[x]-dep[top[x]]+1;
x=anc[top[x]][1];
}
return id[dfn[x]-k];
}
inline int calc(int x,int y,const int &k) {
if(dep[x]<=dep[y]) return 0;
int ret=0;
if(k<block) {
while(y&&(dep[x]-dep[y])%k) y=anc[y][1];
ret=sum[x][k]-sum[y][k];
} else {
while(dep[x]>dep[y]) {
ret+=a[x];
x=father(x,k);
}
}
return ret;
}
inline int query(int x,int y,const int &k) {
const int z=lca(x,y),dis=dep[x]+dep[y]-dep[z]*2;
int ret=calc(x,z,k);
if(dis%k) {
ret+=a[y];
y=father(y,dis%k);
}
ret+=calc(y,anc[z][1],k);
return ret;
}
int main() {
block=sqrt(n=getint());
for(register int i=1;i<=n;i++) a[i]=getint();
for(register int i=1;i<n;i++) {
add_edge(getint(),getint());
}
dfs(1,0);
dfs(1);
for(register int i=1;i<=n;i++) b[i]=getint();
for(register int i=1;i<n;i++) {
printf("%d\n",query(b[i],b[i+1],getint()));
}
return 0;
}
[POI2015]Odwiedziny的更多相关文章
- bzoj4381: [POI2015]Odwiedziny
这题搞了我一下午……因为一些傻X的问题…… 对于步长大于sqrt(n)的询问,我们可以直接暴力求解 然后,我们可以事先预处理出d[u][step]表示u往上跳,每次跳step步,直到跳到不能跳为止,所 ...
- BZOJ4381[POI2015]Odwiedziny——分块+长链剖分
题目描述 给定一棵n个点的树,树上每条边的长度都为1,第i个点的权值为a[i].Byteasar想要走遍这整棵树,他会按照某个1到n的全排列b走n-1次,第i次他会从b[i]点走到b[i+1]点,并且 ...
- BZOJ4381 : [POI2015]Odwiedziny / Luogu3591[POI2015]ODW - 分块+树剖
Solution 在步伐$pace$比较小的时候, 我们发现用前缀和直接维护会很快 而在$pace$比较大的时候, 则暴力往上跳会最优 设$blo= \sqrt{N}$ 若$pace<=blo$ ...
- @bzoj - 4381@ [POI2015] Odwiedziny
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一棵 n 个点的树,树上每条边的长度都为 1 ,第 i 个点 ...
- [Poi2015]
[POI2015]Łasuchy 一看以为是sb题 简单来说就是每个人获得热量要尽量多 不能找别人 首先这道题好像我自己找不到NIE的情况 很容易想到一个优化 如果一个数/2>另一个数 那么一定 ...
- POI2015题解
POI2015题解 吐槽一下为什么POI2015开始就成了破烂波兰文题目名了啊... 咕了一道3748没写打表题没什么意思,还剩\(BZOJ\)上的\(14\)道题. [BZOJ3746][POI20 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- BZOJ 4385: [POI2015]Wilcze doły
4385: [POI2015]Wilcze doły Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 648 Solved: 263[Submit][ ...
- BZOJ 4384: [POI2015]Trzy wieże
4384: [POI2015]Trzy wieże Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 217 Solved: 61[Submit][St ...
随机推荐
- Mac 下 gzip 一个文件
gzip -k xxx.json -k 会保留源文件
- 【bzoj题解】1008 越狱
题目描述 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱. 输入 输入两个整 ...
- 【不知道是啥的NOIP模拟赛】网络入侵
题意是这样的: 给你一棵树,每个边有一个初始的0/1边权.你希望把它弄成一个给定的样子. 你每次可以选一条树链取反,然后问你最少要操作几次. ----------------------------- ...
- Scrapy:运行爬虫程序的方式
Windows 10家庭中文版,Python 3.6.4,Scrapy 1.5.0, 在创建了爬虫程序后,就可以运行爬虫程序了.Scrapy中介绍了几种运行爬虫程序的方式,列举如下: -命令行工具之s ...
- C# LINQ语句
1.select 和 selectMany SelectMany() 将中间数组序列串联为一个最终结果值,其中包含每个中间数组中的每个值 2.join语句 from x in xx join d in ...
- virtualenv,virtualenvwrapper安装及使用
1.安装 # 安装: (sudo) pip install virtualenv virtualenvwrapper # centos7下 pip install virtualenv virtual ...
- OA项目Ioc DI(二)
依赖注入:属性和构造函数的注入 一个简单的Demo: IUserInfoDal接口: public interface IUserInfoDal { void Show(); string Name ...
- android练习
package com.example.wang.testapp2; import android.app.AlertDialog; import android.content.DialogInte ...
- ueditor初始化
一.下载文件复制到项目中 二.复制表情文件 三.复制列表图片 四.修改ueditor.config.js文件 五.接着修改net文件下config.json文件 六.完蛋了,不支持IE8,版本替换为了 ...
- USACO 6.4 Wisconsin Squares
Wisconsin Squares It's spring in Wisconsin and time to move the yearling calves to the yearling past ...