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 ...
随机推荐
- Post页面爬取失败__编码问题
python3爬取Post页面时, 报以下错误 "POST data should be bytes or an iterable of bytes. It cannot be of typ ...
- 设置ubuntu12.04的dasher-自动隐藏,左上角
点击右上角的齿轮,--> “system setting”--“Appearance” 在“Look”标签中: Theme:Ambiance Launch icon size :32 选择桌面背 ...
- selenium2中的TestNg注解和数据驱动的简介及使用
TestNg常用注解介绍,先来张图: 先看一下,以上各个注释的运行次序: @Test 表示的意义: 1.表示示该方法是一个测试方法,在运行时,会自动的运行有@Test注脚的方法. 示例: @Be ...
- Java程序的结构和执行
目录 Java程序的结构 Java程序的执行 source code -- compiler -- class file -- JVM compiler JVM Java语法 数据类型 数据的存储 堆 ...
- ASP.Net 更新页面输出缓存的几种方法
ASP.Net 自带的缓存机制对于提高页面性能有至关重要的作用,另一方面,缓存的使用也会造成信息更新的延迟.如何快速更新缓存数据,有时成了困扰程序员的难题.根据我的使用经验,总结了下面几种方法,概括了 ...
- python补漏----isinstance 和 issubclass
一.isinstance Python 中的isinstance函数 isinstance是Python中的一个内建函数 语法: isinstance(object, classinfo) 如果参数o ...
- python学习-- {% csrf_token %}
1.不推荐禁用掉django中的CSRF. 2.我们可以再html页面的form表单中添加csrf_token,带着表单的请求一起发送到服务器去验证. <form enctype=" ...
- 2018天梯赛第一次训练题解和ac代码
随着评讲的进行代码和题解会逐步放上来 2018天梯赛第一次训练 1001 : 进制转换 Time Limit(Common/Java):1000MS/10000MS Memory Limit: ...
- 九度oj 题目1397:查找数段
题目描述: 在BaiDu搜索引擎里,如何提高搜索效率是研发人员为之奋斗的目标.现在,JOBDU密码库里也有一段数字片段S(0<长度<=100,000),HQ想通过智能搜索得到包含关键字P( ...
- 学习 WebService 第四步:利用WSDL(URL)生成WebService客户端<初级>
我用的是最简单的方法,利用jdk的命令wsimport -keep -p 包路径 -d 代码存放位置 WSDL网址 蓝色是命令,粉色是存放位置,橘色是URL C:\Program Files\IBM\ ...