4381: [POI2015]Odwiedziny

18 篇文章 0 订阅
11 篇文章 0 订阅

4381: [POI2015]Odwiedziny

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 392   Solved: 182
[ Submit][ Status][ Discuss]

Description

给定一棵n个点的树,树上每条边的长度都为1,第i个点的权值为a[i]。
Byteasar想要走遍这整棵树,他会按照某个1到n的全排列b走n-1次,第i次他会从b[i]点走到b[i+1]点,并且这一次的步伐大小为c[i]。
对于一次行走,假设起点为x,终点为y,步伐为k,那么Byteasar会从x开始,每步往前走k步,如果最后不足k步就能到达y,那么他会一步走到y。
请帮助Byteasar统计出每一次行走时经过的所有点的权值和。

Input

第一行包含一个正整数n(2<=n<=50000)。表示节点的个数。
第二行包含n个正整数,其中第i个数为a[i](1<=a[i]<=10000),分别表示每个点的权值。
接下来n-1行,每行包含两个正整数u,v(1<=u,v<=n),表示u与v之间有一条边。
接下来一行包含n个互不相同的正整数,其中第i个数为b[i](1<=b[i]<=n),表示行走路线。
接下来一行包含n-1个正整数,其中第i个数为c[i](1<=c[i]<n),表示每次行走的步伐大小。

Output

包含n-1行,每行一个正整数,依次输出每次行走时经过的所有点的权值和

Sample Input

5
1 2 3 4 5
1 2
2 3
3 4
3 5
4 1 5 2 3
1 3 1 1

Sample Output

10
6
10
5

HINT

鸣谢Claris

Source

[ Submit][ Status][ Discuss]



对于询问分类讨论,如果k >= sqrt(n),可以暴力去做,反正走sqrt(n)次就完了

如果k < sqrt(n),预处理f[i][j]:从点i,每次往上走j格,走到根能得到的权值和,询问的时候++--就好了

写的话,,对于一段路径(x,y),可以先把y提上去一点(如果最后一步小于k),然后x,y一起往lca处快速移动

复杂度O(nsqrt(n)logn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn = 5E4 + 50;
const int T = 16;
const int N = 251;

int n,a[maxn],b[maxn],c[maxn],fa[maxn][T],f[maxn][N],L[maxn];

vector <int> v[maxn];

void Dfs(int x)
{
	for (int i = 1; i < T; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
	for (int i = 1,y = x; i < N; i++) y = fa[y][0],f[x][i] = f[y][i] + a[x];
	for (int i = 0; i < v[x].size(); i++)
	{
		int to = v[x][i]; if (to == fa[x][0]) continue;
		L[to] = L[x] + 1; fa[to][0] = x; Dfs(to);
	}	
}

int LCA(int p,int q)
{
	if (L[p] < L[q]) swap(p,q);
	for (int i = T - 1; i >= 0; i--)
		if (L[p] - (1<<i) >= L[q])
			p = fa[p][i];
	if (p == q) return p;
	for (int i = T - 1; i >= 0; i--)
		if (fa[p][i] != fa[q][i])
			p = fa[p][i],q = fa[q][i];
	return fa[p][0];
}

int Quickfa(int x,int y)
{
	for (int now = 0; y; y >>= 1,++now)
		if (y&1) x = fa[x][now]; return x;
}

int query(int x,int y,int k)
{
	if (k < N) return f[x][k] - f[y][k] + a[y];
	else
	{
		int ret = a[x];
		while (x != y)
			x = Quickfa(x,k),ret += a[x];
		return ret;
	}
}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	n = getint();
	for (int i = 1; i <= n; i++) a[i] = getint();
	for (int i = 1; i < n; i++)
	{
		int x = getint(),y = getint();
		v[x].push_back(y);
		v[y].push_back(x);
	}
	L[n/2] = 1; Dfs(n/2);
	for (int i = 1; i <= n; i++) b[i] = getint();
	for (int i = 1; i < n; i++) c[i] = getint();
	
	for (int i = 1; i < n; i++)
	{
		int x = b[i],y = b[i+1],k = c[i],Ans = 0;
		int lca = LCA(x,y),dis = L[x] + L[y] - (L[lca]<<1);
		if (dis % k != 0) Ans += a[y],y = Quickfa(y,dis % k);
		int A = Quickfa(x,(L[x] - L[lca]) / k * k); Ans += query(x,A,k);
		if (L[y] <= L[lca]) {printf("%d\n",Ans); continue;}
		int B = Quickfa(y,(L[y] - L[lca]) / k * k); Ans += query(y,B,k); 
		if (A == B) Ans -= a[A]; printf("%d\n",Ans);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值