@(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\).

\[Output
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的更多相关文章

  1. codechef January Challenge 2014 Sereja and Graph

    题目链接:http://www.codechef.com/JAN14/problems/SEAGRP [题意] 给n个点,m条边的无向图,判断是否有一种删边方案使得每个点的度恰好为1. [分析] 从结 ...

  2. Codechef March Challenge 2014——The Street

    The Street Problem Code: STREETTA https://www.codechef.com/problems/STREETTA Submit Tweet All submis ...

  3. 【分块+树状数组】codechef November Challenge 2014 .Chef and Churu

    https://www.codechef.com/problems/FNCS [题意] [思路] 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数 查询时求前缀和,对于 ...

  4. CodeChef November Challenge 2014

    重点回忆下我觉得比较有意义的题目吧.水题就只贴代码了. Distinct Characters Subsequence 水. 代码: #include <cstdio> #include ...

  5. 刷漆(Codechef October Challenge 2014:Remy paints the fence)

    [问题描述] Czy做完了所有的回答出了所有的询问,结果是,他因为脑力消耗过大而变得更虚了:).帮助Czy恢复身材的艰巨任务落到了你的肩上. 正巧,你的花园里有一个由N块排成一条直线的木板组成的栅栏, ...

  6. [Codechef October Challenge 2014]刷漆

    问题描述 Czy做完了所有的回答出了所有的询问,结果是,他因为脑力消耗过大而变得更虚了:).帮助Czy恢复身材的艰巨任务落到了你的肩上. 正巧,你的花园里有一个由N块排成一条直线的木板组成的栅栏,木板 ...

  7. 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 ...

  8. AC日记——The Street codechef March challenge 2014

    The Street 思路: 动态开节点线段树: 等差序列求和于取大,是两个独立的子问题: 所以,建两颗线段树分开维护: 求和:等差数列的首项和公差直接相加即可: 取大: 对于线段树每个节点储存一条斜 ...

  9. CODECHEF Nov. Challenge 2014 Chef & Churu

    @(XSY)[分塊] Hint: 題目原文是英文的, 寫得很難看, 因此翻譯為中文. Input Format First Line is the size of the array i.e. \(N ...

随机推荐

  1. LeetCode(275)H-Index II

    题目 Follow up for H-Index: What if the citations array is sorted in ascending order? Could you optimi ...

  2. hihocoder1174 拓扑排序1

    #1174 : 拓扑排序·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 由于今天上课的老师讲的特别无聊,小Hi和小Ho偷偷地聊了起来. 小Ho:小Hi,你这学期有选 ...

  3. 静态代码扫描工具使用教程 - SonarQube+SonarScanner

    预置条件: Jdk已安装 Mysql已安装 1. 下载 SonarQube和Sonar scanner. SonarQube: http://www.sonarqube.org/downloads/ ...

  4. Leetcode 424.替换后的最长重复字符

    替换后的最长重复字符 给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次.在执行上述操作后,找到包含重复字母的最长子串的长度. 注意:字符串长度 和 ...

  5. BIT+DP

    2018CCPC网络赛 J - YJJ's Salesman HDU - 6447 YJJ is a salesman who has traveled through western country ...

  6. JQUERY杂技

    JQUERY小技巧 this.value jsobject.val() #aaa:eq(2) 选择第三个id为aaa的元素 $("input")只选择input标签.如:<i ...

  7. Linux定时任务Crontab命令详解 转

      linux 系统则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的.另 外, 由于使用者自己也可以设置计划任务,所 ...

  8. 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  9. 报错:java.lang.IllegalStateException

    java.lang.IllegalStateException: BeanFactory not initialized or already closed - call '“refresh”' be ...

  10. [HDU4362] Palindrome subsequence (区间DP)

    题目链接 题目大意 给你几个字符串 (1<len(s)<1000) ,要你求每个字符串的回文序列个数.对于10008取模. Solution 区间DP. 比较典型的例题. 状态定义: 令 ...