CODECHEF Oct. Challenge 2014 Children Trips
@(XSY)[分塊, 倍增]
Description
There's a new trend among Bytelandian schools. The "Byteland Touristic Bureau" has developed a new project for the high-schoolers. The project is so-called "Children's Trips".
The project itself is very simple: there are some touristic routes in Byteland, and N touristic campuses (numbered from 1 to N). For the sake of economy, there are exactly N-1 road between them. Of course, even having this given, it is possible to travel from any touristic campus to any other one. Moreover, for the sake of safety, each road is no longer than 2 kilometers.
When some student wants to travel, he first chooses his starting campus - he is been delivered there (say) by a helicopter. He chooses his final destination campus as well. From his final destination, he will be transported to his home by (say) a helicopter, again. So that pupil won't travel any extra distance by foot. When the start and the finish are chosen and the pupil is delivered, he starts his moving by the only route. None of pupils is infinitely strong, so first the pupil looks at the map of the touristic routes, and then he chooses the furthest campus on his way that he can reach during the current day (by safety regulations, it is strictly prohibited to sleep not at the campus because there can be a little trouble with werewolves), and moves there. Then the new day begins, and it repeats till the moment when the destination is reached.
Of course, not all the students created equal. Somebody is good in math, somebody in English, somebody in PE. So it's quite natural that all high-schoolers has different strengths.
We call the strength is the maximal number of kilometers that the pupil can pass in a day. And now you're given a lot of queries from the children. For every query, you are given the starting campus, the final campus and the strength. You are requested to calculate the number of days for every trip. The map of the campuses and the distances between them will be given to you as well.
Input
The first line of input contains the integer \(N\), denoting the number of campuses.
The next \(N-1\) lines contain triples of the form \(X\) \(Y\) \(D\) with the meaning that there is a road between the X-th and the Y-th campus with the length \(D\) kilometers.
Then there is a line with a single integer \(M\), denoting the number of queries.
Then, there are \(M\) lines with the triples of the form \(S\) \(F\) \(P\) with the meaning that the trip starts at the campus \(S\), ends at the campus \(F\) and the student has the strength of \(P\).
For every query, please output the number of days on a separate line.
Constraints
$1 ≤ N, M ≤ 100000$
$1 ≤ X, Y, S, F ≤ N$
$1 ≤ D ≤ 2$
$2 ≤ P ≤ 2*N$
##Example
###Input:
```dos
5
1 2 1
2 3 2
1 4 2
4 5 1
5
1 5 3
1 3 2
2 5 4
1 2 10
4 5 2
```
###Output:
```dos
1
2
1
1
1
```
##Solution
翻譯一下題意:
>有一棵每条边的边权分别为$1$或$2$的共有$n$个节点的树, 对于一个询问, 给出起点$u$和终点$v$, 以及每一天最多走的路程$k$. 规定每天的结束点必须在树的节点上, 问最少要几天走完所有路程.
由於邊的權值只能為$1$或$2$, 因此可以考慮採用時間複雜度帶根號的算法.
>对$p$分情况进行讨论
>1. $p \ge \sqrt{n}$
>最多总共走$\sqrt{n}$天, 对于每一天倍增最远可以走到哪里即可, 并统计走的天数.
>2. $p \le sqrt(n)$
>对于每次询问的$p$, 暴力求出从每个点出发, 最多走$p$距离最远可以到达的最远位置. 再用倍增求出$f[i][j]$数组, 表示从点$i$出发, 走$2 ^ j$天可以到达的最远位置. 最后跑一次倍增解决.
>注意在进行这种计算之前, 先要将$p$从小到大排序. 这样每次计算就可以省去之前已经进行过的部分. 同时, 对于两个相同的$p$值, 不要重复求$f$数组, 否则会超时.
>时间复杂度$O \left( n * \sqrt{n} * log(n) \right)$
```cpp
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
int x = 0, flag = 1;
char c;
while(! isdigit(c = getchar()))
if(c == '-')
flag *= - 1;
while(isdigit(c))
x = x * 10 + c - '0', c = getchar();
return x * flag;
}
void println(int x)
{
if(x < 0)
putchar('-'), x *= - 1;
if(x == 0)
putchar('0');
int ans[1 << 5], top = 0;
while(x)
ans[top ++] = x % 10, x /= 10;
for(; top; top --)
putchar(ans[top - 1] + '0');
putchar('\n');
}
const int N = 1 << 17, M = 1 << 17;
int n;
int head[N];
int top;
struct edge
{
int v, w, next;
}G[N << 1];
inline void addEdge(int u, int v, int w)
{
G[top].v = v, G[top].w = w, G[top].next = head[u];
head[u] = top ++;
}
struct data
{
int u, dis;
}st[N][17];
int dep[N];
int disToRoot[N];
void dfs(int u, int pre, int w)
{
st[u][0].u = pre;
st[u][0].dis = w;
dep[u] = dep[pre] + 1;
disToRoot[u] = disToRoot[pre] + w;
for(int i = head[u]; ~ i; i = G[i].next)
if(G[i].v != pre)
dfs(G[i].v, u, G[i].w);
}
inline void getSt()
{
for(int i = 1; i < 17; i ++)
for(int j = 1; j <= n; j ++)
st[j][i].u = st[st[j][i - 1].u][i - 1].u,
st[j][i].dis = st[j][i - 1].dis + st[st[j][i - 1].u][i - 1].dis;
}
struct query
{
int id, s, t, p;
inline friend int operator <(query a, query b)
{
return a.p < b.p;
}
}a[M];
int getLca(int u, int v)
{
if(dep[u] < dep[v])
swap(u, v);
for(int i = 17 - 1; ~ i; i --)
if(dep[u] - (1 << i) >= dep[v])
u = st[u][i].u;
if(u == v)
return u;
for(int i = 17 - 1; ~ i; i --)
if(st[u][i].u != st[v][i].u)
u = st[u][i].u, v = st[v][i].u;
return st[u][0].u;
}
inline int climb(int &u, int lca, int p)
{
int ret = 0;
while(1)
{
if(disToRoot[u] - disToRoot[lca] < p)
break;
int left = p;
for(int i = 17 - 1; ~ i; i --)
if(left >= st[u][i].dis)
left -= st[u][i].dis, u = st[u][i].u;
ret ++;
}
return ret;
}
int ans[M];
int f[N][17];
inline int jump(int &u, int lca)
{
int ret = 0;
for(int i = 17 - 1; ~ i; i --)
if(dep[f[u][i]] > dep[lca])
ret += 1 << i, u = f[u][i];
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("childrenTrip.in", "r", stdin);
freopen("childrenTrip.out", "w", stdout);
#endif
n = read();
memset(head, - 1, sizeof(head));
top = 0;
for(int i = 1; i < n; i ++)
{
int u = read(), v = read(), w = read();
addEdge(u, v, w), addEdge(v, u, w);
}
dep[1] = - 1;
disToRoot[1] = 0;
dfs(1, 1, 0);
getSt();
int m = read();
for(int i = 0; i < m; i ++)
a[i].id = i, a[i].s = read(), a[i].t = read(), a[i].p = read();
sort(a, a + m);
int p;
for(p = 0; p < m; p ++)
if(a[p].p > (int)sqrt(n))
break;
for(int i = p; i < m; i ++)
{
int lca = getLca(a[i].s, a[i].t);
ans[a[i].id] = climb(a[i].s, lca, a[i].p) + climb(a[i].t, lca, a[i].p)
+ (disToRoot[a[i].s] + disToRoot[a[i].t] - 2 * disToRoot[lca] + a[i].p - 1) / a[i].p;
}
for(int i = 1; i <= n; i ++)
f[i][0] = i;
int last = 0;
for(int i = 0; i < p; i ++)
{
if(a[i].p != last)
{
for(int j = 1; j <= n; j ++)
{
int rest = a[i].p - (disToRoot[j] - disToRoot[f[j][0]]);
int u = f[j][0];
for(; ;)
{
rest -= st[u][0].dis;
u = st[u][0].u;
if(rest >= 0)
f[j][0] = u;
if(rest <= 0 || ! dep[u])
break;
}
}
for(int j = 1; j < 17; j ++)
for(int k = 1; k <= n; k ++)
f[k][j] = f[f[k][j - 1]][j - 1];
last = a[i].p;
}
int lca = getLca(a[i].s, a[i].t);
ans[a[i].id] = jump(a[i].s, lca) + jump(a[i].t, lca)
+ (disToRoot[a[i].s] + disToRoot[a[i].t] - 2 * disToRoot[lca] + a[i].p - 1) / a[i].p;
}
for(int i = 0; i < m; i ++)
println(ans[i]);
}
```\]
CODECHEF Oct. Challenge 2014 Children Trips的更多相关文章
- codechef January Challenge 2014 Sereja and Graph
题目链接:http://www.codechef.com/JAN14/problems/SEAGRP [题意] 给n个点,m条边的无向图,判断是否有一种删边方案使得每个点的度恰好为1. [分析] 从结 ...
- Codechef March Challenge 2014——The Street
The Street Problem Code: STREETTA https://www.codechef.com/problems/STREETTA Submit Tweet All submis ...
- 【分块+树状数组】codechef November Challenge 2014 .Chef and Churu
https://www.codechef.com/problems/FNCS [题意] [思路] 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数 查询时求前缀和,对于 ...
- CodeChef November Challenge 2014
重点回忆下我觉得比较有意义的题目吧.水题就只贴代码了. Distinct Characters Subsequence 水. 代码: #include <cstdio> #include ...
- 刷漆(Codechef October Challenge 2014:Remy paints the fence)
[问题描述] Czy做完了所有的回答出了所有的询问,结果是,他因为脑力消耗过大而变得更虚了:).帮助Czy恢复身材的艰巨任务落到了你的肩上. 正巧,你的花园里有一个由N块排成一条直线的木板组成的栅栏, ...
- [Codechef October Challenge 2014]刷漆
问题描述 Czy做完了所有的回答出了所有的询问,结果是,他因为脑力消耗过大而变得更虚了:).帮助Czy恢复身材的艰巨任务落到了你的肩上. 正巧,你的花园里有一个由N块排成一条直线的木板组成的栅栏,木板 ...
- Codechef December Challenge 2014 Chef and Apple Trees 水题
Chef and Apple Trees Chef loves to prepare delicious dishes. This time, Chef has decided to prepare ...
- AC日记——The Street codechef March challenge 2014
The Street 思路: 动态开节点线段树: 等差序列求和于取大,是两个独立的子问题: 所以,建两颗线段树分开维护: 求和:等差数列的首项和公差直接相加即可: 取大: 对于线段树每个节点储存一条斜 ...
- CODECHEF Nov. Challenge 2014 Chef & Churu
@(XSY)[分塊] Hint: 題目原文是英文的, 寫得很難看, 因此翻譯為中文. Input Format First Line is the size of the array i.e. \(N ...
随机推荐
- 20个必不可少的Python库也是基本的第三方库
个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz写的最富盛名的http库.每个Python程序员都应该有它. Scrapy. ...
- static 的三个作用
1).用于声明函数体内的变量为静态局部变量,存储在静态数据存储区,在函数被调用过程中维持其值保持不变 2).在文件内(函数体外)被声明为静态的变量,可以被文件内的所有函数访问,但不能被其他文件的函数访 ...
- 针对NM_CUSTOMDRAW消息的学习
消息的形式:1 窗口消息,2 命令消息,3 WM_NOTIFY消息,4 自定义消息 我们的NM_CUSTOMDRAW消息就是就属于第三种WM_NOTIFY消息,而添加消息映射的方法分为两种: BEGI ...
- 【JavaScript】关于 eval()执行JavaScript语句的一次实验测试
实验主题: eval() 函数可以计算某个字符串,并执行其中的 JavaScript 代码.该函数只接受原始字符串作为参数,如果 string 不是原始字符串,那么该方法将不作任何的改变的返回.因此请 ...
- 紫书第三章训练1 E - DNA Consensus String
DNA (Deoxyribonucleic Acid) is the molecule which contains the genetic instructions. It consists of ...
- 为什么要用全文搜索引擎:全文搜索引擎 VS 数据库管理系统
正文一:Full Text Search Engines vs. DBMS 发表于2009年 正文二:Elasticsearch - A High-Performance Full-Text Sea ...
- 学习C++的第四天
1.头文件中的 #ifndef/#define/#endif 防止该头文件被重复引用” //文件路径名:el_1\hello.h #ifndef _HELLO /////如果没有定义 _HELLO文件 ...
- golang语法要点笔记
golang学习笔记 读<go学习笔记第四版> <学习go语言> <gopl-zh><Go语言实战>记录 多变量赋值时,先计算所有相关值,然后再从左到右 ...
- 【bzoj4319】cerc2008 Suffix reconstruction 贪心
题目描述 话说练习后缀数组时,小C 刷遍 poj 后缀数组题, 各类字符串题闻之丧胆.就在准备对敌方武将发出连环杀时,对方一记无中生有,又一招顺手牵羊,小C 程序中的原字符数组就被牵走了.幸运的是,小 ...
- 【Luogu】P3705新生舞会(费用流+分数规划+二分答案)
题目链接 本来以为自己可以做出来,结果……打脸了 (貌似来wc立了好几个flag了,都没竖起来) 不过乱蒙能蒙出一个叫“分数规划”的东西的式子还是很开心的 观察$C=\frac{a_{1}+a_{2} ...