@(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. linux学习-使用者身份切换

    在 Linux 系统当中还要作身份的变换?这是为啥?可能有底下几个原因啦! 使用一般账号:系统平日操作的好习惯 用较低权限启动系统服务 软件本身的限制 由于上述考虑,所以我们都是使用一般账号登入系统的 ...

  2. 使用supervisor方便调试程序

    调试过程中,有时需要修改代码,并时刻看到运行效果.如果每次终止程序又重启,会很麻烦. 可以使用supervisor,它可以监听代码文件,一旦发生改动会自动重启程序. 安装supervisor命令: n ...

  3. luogu1736 创意吃鱼法

    好的题解使人一下就懂啊-- s1[i][j]表示(i,j)最多向左(或右)延伸多少个格子,使这些格子中的数都是0(不包括(i,j)) s2[i][j]表示(i,j)最多向上延伸多少个格子,使这些格子中 ...

  4. Vmware复制完好的linux目录后网卡操作

    目录 Vmware复制完好的linux目录后网卡操作 修改/etc/udev/rules.d/70-persistent-net.rules 修改网卡配置文件 重启查看 Vmware复制完好的linu ...

  5. python redis中blpop和lpop的区别

    python redis 中blpop返回的是元组对象,因此返回的时候注意 lpop返回的是对象

  6. 【瓜分5000元奖金】Wannafly挑战赛13

    链接:https://www.nowcoder.com/acm/contest/80/A来源:牛客网 zzy的小号 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他 ...

  7. STL之map容器的详解

    一.关于map的介绍 map是STL的 一个容器,和set一样,map也是一种关联式容器.它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键 字的值)的数据 ...

  8. 【bzoj3252】攻略 贪心+DFS序+线段树

    题目描述 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某 ...

  9. 【bzoj3751】[NOIP2014]解方程 数论

    题目描述 已知多项式方程: a0+a1*x+a2*x^2+...+an*x^n=0 求这个方程在[1,m]内的整数解(n和m均为正整数). 输入 第一行包含2个整数n.m,每两个整数之间用一个空格隔开 ...

  10. CS231n笔记 Lecture 1 Introduction

    主题有关 这一讲主要是介绍性质的,虽然大多数概念以前听说过,但还是在他们的介绍中让我有如下一些认识,所谓温故而知新,不无道理: IMAGENET Feifei Li的团队首先爬取.标注了IMAGENE ...