DAY5测试T2 Tree(LCA+线段树/树上差分)

【问题描述】
小s是A星球的霸主。A星球上有n个城市,城市之间有一些道路。小s发现城市和道路刚好组成了一棵树。并且他发现如果有任意一条道路损坏,城市和城市之间就不连通了。A星球上还有m对工作站(A, B)。每对工作站在工作的时候,需要人员从A城市走到B城市。
现在A星球有Q个任务,每个任务可以由第L对工作站到第R对工作站任意一个来完成。小s想知道对于每个任务,损坏了哪些边会导致任务不能完成。他想把这个问题交给你,但你只需要告诉他损坏的边的总长度即可。
【输入格式】
输入的第一行包含1个整数n,表示城市个数。
接下来n-1行,每行包含3个整数x, y, z,表示边(x, y)和边的长度z。
接下来一行一个整数m,表示m对工作站。
接下来m行,每行包含两个整数A, B
接下来一行一个整数Q,表示任务数。
接下来Q行,每行两个整数L,R。表示第i个任务可以由第L对到第R对工作站完成。
【输出格式】
输出Q行,第i行表示第i个任务的答案。
【样例输入】
4
1 2 5
2 3 2
1 4 3
2
1 2
3 4
1
1 2
【样例输出】
5
【数据范围与约定】
30%: n, m, Q <= 200
60%: n, m, Q <= 1000
100%: n, m, Q <= 50000


一看到题就想起之前做的NOIP2015 运输计划了。简化题意为求第L~R条给定路径公共边的权值和。那么跑一遍dfs预处理出 dis[ i ] 数组表示节点 i 到根节点的距离,则可得每对工作站的路径长。
然后开始读入查询,对于每对查询都做一遍差分。差分数组为 dif 。例如对于某对工作站 ( x, y ),dif [ x ]+=1, dif [ y ]+=1 ,dif[ LCA( x, y ) ]-=2。处理完 [ L,R ] 后求一遍子树权值和。若某个点权值和等于 R-L+1 ,则其到父节点的那条边必为公共边。由于倍增求LCA中会处理出数组 f[ x][ 0 ],故易得其父节点。枚举 n 求和即可。
时间复杂度大致是 O( nq ),能过六十分。但是要开long long。以后这种累加的都应该注意一点。

正解很绝妙。
通过观察可以发现对于两条路径:(x1,y1)和(x2,y2),在LCA(x1,x2),LCA(x1,y2),LCA(y1,x2),LCA(y1,y2)中取深度最大的两个点,这两点之间的路径即为公共路径。画个图就能明白。
这么说题目暗示还是给的很明显的,“第L对到第R对”,还有这么大的查询量,肯定要用数据结构维护了。我们考虑线段树。
用线段树维护 1~m 对工作站。每段区间(x,y)都表示第 x 对~第 y 对按上述方法求出的公共路径的两个端点。剩下都是线段树的常规操作。

调了很久……居然是因为忘记删一个比较微妙的打表。

#include<bits/stdc++.h>
using namespace std;

const int maxn=50001;

int n,m,q;
int x,y,z;
int Link[maxn];
struct edge{
    int y,next,v;
}e[maxn<<1];
int Tot;

int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值