您的位置:首页 > 其它

四叠半神话大系(bfs序+st+在线倍增+二分)(北理16校赛)

2016-05-17 20:18 417 查看
时间限制1秒 内存限制64M

题目描述:

「我们大部分的烦恼,是来自于梦想另一种有可能的人生。把希望寄托于自己的可能性这种不能指望的东西,正是万恶的根源。」

时间突然停止。

我获得了可以在平行世界中穿梭的能力。

宇宙中存在着无数的平行世界,这些世界组成了一个树形的结构,每个世界有一个编号和一个幸福度。

每当我做出选择时,世界会分裂成若干个新的世界。选择会导致幸福度的变化。根据选择的不同,在新的世界里,我可能会变的更加幸福,或者更加不幸。

出于某些原因,我只能在处于相同时间的世界内穿梭,而且只能在由若干个时间单位前的世界分裂来的世界中穿梭。

我要在平行世界中找到一个最幸福的世界,在那里继续生活下去。然而真的存在这样的世界吗?

输入格式:

第一行,一个整数

,表示一共有

个世界。



接下来

行,每行三个整数

,

,

.
表示

号世界下一个时间单位内会走向

号世界,幸福度会变化

。(

,

)

接下来一行,一个整数

,表示接下来有Q个询问。



接下来

行,每行两个整数

,

。表示现在身处

号世界,允许穿梭到从

个时间单位前分裂的所有世界。





数据保证,1号世界是根节点,且1号节点的幸福度是



输出格式:



行,每行一个整数。第

的整数表示第

个询问中,能获得的最大幸福度。

样例输入:

8

1 2 1

2 3 3

1 4 2

1 5 -2

5 6 3

5 7 4

5 8 -2

3

6 1

6 2

5 1

样例输出:

2

4

2

样例解释:






对于第二个询问(6, 2),6号世界2个时间单位前的世界是1号世界,1号世界分裂的所有世界中,与6号世界处在相同时间的是3号、6号、7号、8号世界,其中幸福度最高的是3号世界(0 + 1 + 3 = 4)。
题目大意:
一棵有根树,每个节点有一个权值,现在有若干个询问,对于每一个询问(x,y),求与x节点有相同深度且具有相同第y级祖先的所有节点中,权值的最大值。
解题思路:
用类似在线倍增lca的思路,nlogn预处理,可以在logn内求出他的y级祖先。
相同深度而且有某个公共y级祖先的节点的bfs序是连续的,如果获得了bfs序的区间,可以用rmq求出这个区间节点中的最大权值。
先求出所有点的bfs序,构建这些节点的st,然后二分求出区间的左端点和右端点(随着bfs序的增大他们的y级祖先的bfs序也在增大)每次求祖先logn的,因此查询的复杂度是(logn)^2的,总的复杂度o(qlognlogn)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int maxn = 100050;
const double eps = 1e-6;
int p[maxn][55], head[maxn], tot, val[maxn], vis[maxn], bfsxu, pos[maxn], spos[maxn], mm[maxn];
int maxx[maxn][55];
struct node {
int from, to, next, val;
}e[maxn];
void init()
{
tot = 0; bfsxu = 1; pos[1] = 1; spos[1] = 1;
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(val, 0, sizeof(val));
memset(p, -1, sizeof(p));
}
void add(int u, int v, int w)
{
e[tot].from = u;
e[tot].to = v;
e[tot].next = head[u];
e[tot].val = w;
head[u] = tot++;
}
void dfs(int u)
{
vis[u] = 1;
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (!vis[v])
{
p[v][0] = u;
dfs(v);
}
}
}
void rmq(int n)
{
for (int j = 1; (1 << j) <= n; j++)
for (int i = 1; i <= n; i++)
if (~p[i][j - 1])p[i][j] = p[p[i][j - 1]][j - 1];
}
void st(int n)
{
mm[0] = -1;
for (int i = 1; i <= n; i++)
{
mm[i] = ((i&(i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
maxx[i][0] = val[pos[i]];
}
for (int j = 1; j <= mm
; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
maxx[i][j] = max(maxx[i][j - 1], maxx[i + (1 << (j - 1))][j - 1]);
}
int lca(int x, int y)
{
int pa = x;
while (y&&pa != -1)
{
int low = y&(-y);
pa = p[pa][mm[low]];
y -= low;
}
if (pa == -1)return 0;
return pa;
}
int solve(int x, int y)
{
int k = mm[y - x + 1];
return max(maxx[x][k], maxx[y - (1 << k) + 1][k]);
}
int main()
{
int n, x, y, z, q;
while (~scanf("%d", &n))
{
init();
for (int i = 1; i < n; i++)
{
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
dfs(1);
rmq(n);
queue<int>que;
que.push(1);
while (!que.empty())
{
int u = que.front(); que.pop();
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
val[v] = val[e[i].from] + e[i].val;
pos[++bfsxu] = v; spos[v] = bfsxu;
que.push(v);
}
}
st(n);
scanf("%d", &q);
while (q--)
{
scanf("%d%d", &x, &y);
int fa = lca(x, y), ll, rr;
int l = 1, r = spos[x];
while (l<r)
{
int mid = (l + r) / 2;
if (spos[lca(pos[mid], y)] < spos[fa])l = mid + 1;
else r = mid;
}
ll = l;
l = spos[x], r = n;
while (l<r)
{
int mid = (l + r) / 2;
if (spos[lca(pos[mid], y)]>spos[fa])r = mid - 1;
else l = mid;
if (r == l + 1)
{
if (spos[lca(pos[r], y)] == spos[fa])l = r;
else r = l;
}
}
rr = l;
printf("%d\n", solve(ll, rr));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: