Odwiedziny[POI 2015]
题目描述
给定一棵n个点的树,树上每条边的长度都为1,第i个点的权值为a[i]。
Byteasar想要走遍这整棵树,他会按照某个1到n的全排列b走n-1次,第i次他会从b[i]点走到b[i+1]点,并且这一次的步伐大小为c[i]。
对于一次行走,假设起点为x,终点为y,步伐为k,那么Byteasar会从x开始,每次往前走k步,如果最后不足k步就能到达y,那么他会一次走到y。
请帮助Byteasar统计出每一次行走时经过的所有点的权值和。
输入
- Line 1:一个正整数n(2<=n<=50000)。表示节点的个数。
- Line 2:n个正整数,其中第i个数为ai(1≤ai≤10000),分别表示每个点的权值。
- Line 3~n+1:包含两个正整数u,v(1≤u,v≤n),表示u与v之间有一条边。
- Line n+2:n个互不相同的正整数,其中第i个数为b[i](1≤b[i]≤n),表示行走路线。
- Line n+3:n-1个正整数,其中第i个数为ci(1≤ci<n),表示每次行走的步伐大小。
输出
包含n-1行,每行一个正整数,依次输出每次行走时经过的所有点的权值和
SOL:
我们观察了一波局势,发现这道题有些眼熟。相比大家应该都做过这样一道题:给你一个静态的序列(所谓静态是指这个区间不会做任何的修改),M次给出X,L,K,让你求从X起的L个数的和,这L个数中间两两下表相间K(举个栗子:X=5,L=4,K=3,那么sum=a5+a8+a11+a14)。(N<=10W,M<=10W)
这道题我们的思想就是分块,我们发现当K很大时,我们暴力求和的速度是相当快的。因为我们发现 L<=N/K,我们的暴力复杂度是O(L)的。而K很小时,暴力就很慢了,接近于O(N)。我们又注意到K=1时便是前缀和,可以做到O(1)查询。那么我们不禁想当K很小时我们用前缀和优化(K>1有间距的前缀和相比大家都会)。
我们假设我们采取这样的策略,当K<S时我们用前缀和,K>S时我们采取暴力,那么我们就可以在最坏情况下O(n*s+m*n/s)下解决问题,那么我们解得S=sqrt N时最优。(实际上S取的稍微小一些会更快,因为我们刚刚计算的是最坏情况)
那么我们就可以做这一道题了,同样的思想,当K<sqrt N 时我们预处理,K > sqrt N 时我们便暴力向上跳。
case 1: K<sqrt N 我们预处理每个点 以K为间距向上跳的 答案,x的答案加上y的答案减去lca的答案就是了。
case 1: K>sqrt N 我们暴力做,我们每次用树上倍增的方法 log N 的方法向上跳,暴力统计答案,跳跳就好了。
看代码:
#include<bits/stdc++.h>
#define sight(c) ('0'<=c&&c<='9')
#define eho(x) for (int i=head[x];i;i=net[i])
#define N 50007
#define BRE 237
#define SIZ 21
int a[N],fall[N<<],net[N<<],head[N],tot,f[SIZ][N],dep[N],val[N][BRE],g[BRE][N],
m,rog,ot,r,ans,n,x,y,len[N],k;
inline void read(int &x){
static char c;
for (c=getchar();!sight(c);c=getchar());
for (x=;sight(c);c=getchar()) x=x*+c-;
}
using namespace std;
inline void add(int x,int y){fall[++tot]=y; net[tot]=head[x]; head[x]=tot;}
void dfs(int x,int fa){
f[][x]=fa;dep[x]=dep[fa]+;
eho(x) if(fall[i]^fa) dfs(fall[i],x);
}
void Dfs(int x){
for (int i=;i<=m;i++) val[x][i]=val[g[i][x]][i]+a[x];
eho(x) if (fall[i]^f[][x]) Dfs(fall[i]);
}
void write(int x){if (x<) {putchar(''+x); return;} write(x/); putchar(''+x%);}
inline void writeln(int x){ if (x<) putchar('-'),x*=-; write(x); putchar('\n'); }
inline int lca(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int i=SIZ-;~i;i--) if (dep[f[i][x]]>=dep[y]) x=f[i][x];
if (x==y) return x;
for (int i=SIZ-;~i;i--) if (f[i][x]^f[i][y]) x=f[i][x],y=f[i][y];
return f[][x];
}
inline int up(int x,int k) {if (k<=m)return g[k][x];for (int i=SIZ-;~i;i--) if ((k>>i)&) x=f[i][x];return x;}
inline int rop(int x,int y,int k) {
if (dep[x]<dep[y]) return ;rog=;
if (k<m) {
rog+=val[x][k]; ot=k-(dep[x]-dep[y])%k; rog-=val[k==ot?y:up(y,ot%k)][k];
} else while (dep[x]>dep[y]) rog+=a[x],x=up(x,k);
return rog;
}
void solve(int x,int y,int k){
int L=lca(x,y); r=(dep[x]+dep[y]-(dep[L]<<))%k;
ans=rop(x,L,k);
if (r) ans+=a[y],y=up(y,k);
ans+=rop(y,f[][L],k);
writeln(ans);
}
int main () {
freopen("a.in","r",stdin);
read(n); m=min((int)sqrt(n),BRE-);
for (int i=;i<=n;i++) read(a[i]),g[][i]=a[i];
for (int i=n-;i;i--) read(x),read(y),add(x,y),add(y,x);
dfs(,);
for (int j=;j<SIZ;j++)
for (int i=;i<=n;i++) f[j][i]=f[j-][f[j-][i]];
memcpy(g[],f[],sizeof f[]);
for (int j=;j<=m;j++)
for (int i=;i<=n;i++) g[j][i]=g[][g[j-][i]];
Dfs();
for (int i=;i<=n;i++) read(len[i]);
for (int i=;i<n;i++) read(k),
solve(len[i],len[i+],k);
return ;
}
Odwiedziny[POI 2015]的更多相关文章
- [BZOJ 3747] [POI 2015] Kinoman【线段树】
Problem Link : BZOJ 3747 题解:ZYF-ZYF 神犇的题解 解题的大致思路是,当区间的右端点向右移动一格时,只有两个区间的左端点对应的答案发生了变化. 从 f[i] + 1 到 ...
- [POI 2015]Kinoman
Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l< ...
- 解题:POI 2015 PUS
题面 还以为是差分约束,原来拓扑排序也能解决这样的问题=.= 类似差分约束的建图方式,我们把大小关系看做有向边.这样一来图上是不允许存在环的,于是我们可以做拓扑排序.然后问题来了,边数非常大,根本建不 ...
- 解题:POI 2015 Pieczęć
题面 发现好像没有什么好做法,那就模拟么=.= 以印章左上角的'x'为基准,记录印章上'x'的相对位置模拟.记录相对位置是因为可能有这种情况↓ 直接模拟是会漏掉的=.= #include<cst ...
- 解题:POI 2015 Kinoman
题面 发现每种电影只在两场之间产生贡献(只有$pos$的一场的就在$[pos,n]$产生贡献).那么我们针对每个位置$i$求出这场电影下一次出现的位置$nxt[i]$,然后每次更新一下,求整个区间的最 ...
- POI题解整合
我也不知道为啥我就想把POI的题全都放到一篇blog里写完. POI 2005 SAM-Toy Cars 贪心,每次选下次出现最晚的. POI 2006 KRA-The Disks 箱子位置单调,所以 ...
- POI2015题解
POI2015题解 吐槽一下为什么POI2015开始就成了破烂波兰文题目名了啊... 咕了一道3748没写打表题没什么意思,还剩\(BZOJ\)上的\(14\)道题. [BZOJ3746][POI20 ...
- 2015 German Collegiate Programming Contest (GCPC 15) + POI 10-T3(12/13)
$$2015\ German\ Collegiate\ Programming\ Contest\ (GCPC 15) + POI 10-T3$$ \(A.\ Journey\ to\ Greece\ ...
- 自话自说——POI使用需要注意一个地方
2015.12.1 天气 不怎么好 心情跟天气一样.知道为什么吗,因为昨晚一晚没睡你懂吗... 今天在用POI操作excel的时候,遇到了一个很恶心的地方,这个地方真的有那种让我不相信编程的感觉 ...
随机推荐
- 算法提高 9-3摩尔斯电码 map
算法提高 9-3摩尔斯电码 时间限制:1.0s 内存限制:256.0MB 问题描述 摩尔斯电码破译.类似于乔林教材第213页的例6.5,要求输入摩尔斯码,返回英文.请不要使用"z ...
- KD-tree详解
转载自:http://blog.csdn.NET/zhjchengfeng5/article/details/7855241 首先来一个问题: 给定平面上一个点集 E ,还有一个定点 V ,怎么在一群 ...
- 学习python登录demo
要求编写登录接口 : 1. 输入用户名和密码 2.认证成功后显示欢迎信息 3.用户名输错,提示用户不存在,重新输入(5次错误,提示尝试次数过多,退出程序) 4.用户名正确,密码错误,提示密码错误,重新 ...
- CS Round#53 E Maxor
题意:给你N个数,你可以从中选出两个数将它们or起来得到M,求M的最大值及得到最大值的方案数. 刚了半个小时得到了一个貌似时O(N log max(Ai)^2)的方法,想了想发现貌似只能做出第一问,但 ...
- springBoot数据库连接池常用配置
在配置文件中添加配置如下(我使用的是多数据源): spring.datasource.primary.url=jdbc\:mysql\://localhost\:3306/test?useUnicod ...
- Linux用户管理的复习时间
所谓三天不练手生,你还记得关于Linux用户管理的所有知识吗?现在就来跟我一起复习一下吧! 1.常用配置文件 用户信息文件: /etc/password 密码文件: /etc/shadow 用户组文件 ...
- Docker: 限制容器可用的 CPU
默认情况下容器可以使用的主机 CPU 资源是不受限制的.和内存资源的使用一样,如果不对容器可以使用的 CPU 资源进行限制,一旦发生容器内程序异常使用 CPU 的情况,很可能把整个主机的 CPU 资源 ...
- [睡前灵感and发散思维]由一个简单的数组比较问题而想到的
前言 据说,一只优秀的程序猿往往会有这样的经历,白天遇到一个绞尽脑汁也无法解决的问题,晚上睡了后,半夜在梦中会灵感涌现,立马起床,打开电脑,一气呵成.第二天如果不看注释,完全不知道自己找到了如此巧妙地 ...
- 《Linux Device Drivers》第十八章 TTY驱动程序——note
简单介绍 tty设备的名称是从过去的电传打字机缩写而来,最初是指连接到Unix系统上的物理或虚拟终端 Linux tty驱动程序的核心紧挨在标准字符设备驱动层之下,并提供了一系列的功能,作为接口被终端 ...
- Spring MVC新手教程(二)
第一篇文章宏观讲了Spring MVC概念,以及分享了一个高速入门的样例. 这篇文章主要来谈谈Spring MVC的配置文件. 首先来谈谈web.xml: web项目启动时自己主动载入到内存中的信息, ...