发展城市

【问题描述】

众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市。

Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道。机智的Hzwer在宾馆中修建了N-1条隧道,也就是说,宾馆和隧道形成了一个树形结构。

Hzwer有时候会花一天时间去视察某个城市,当来到一个城市之后,Hzwer会分析这些宾馆的顾客情况。对于每个顾客,Hzwer用三个数值描述他:(S, T, V)表示该顾客这天想要从宾馆S走到宾馆T,他的速度是V。

Hzwer需要做一些收集一些数据,这样他就可以规划他接下来的投资。

其中有一项数据就是收集所有顾客可能的碰面次数。

每天清晨,顾客同时从S出发以V的速度前往T(注意S可能等于T),当到达了宾馆T的时候,顾客显然要找个房间住下,那么别的顾客再经过这里就不会碰面了。特别的,两个顾客同时到达一个宾馆是可以碰面的。同样,两个顾客同时从某宾馆出发也会碰面。

【输入格式】

第一行一个正整数T(1<=T<=20),表示Hzwer发展了T个城市,并且在这T个城市分别视察一次。

对于每个T,第一行有一个正整数N(1<=N<=10^5)表示Hzwer在这个城市开了N个宾馆。

接下来N-1行,每行三个整数X,Y,Z表示宾馆X和宾馆Y之间有一条长度为Z的隧道

再接下来一行M表示这天顾客的数量。

紧跟着M行每行三个整数(S, T, V)表示该顾客会从宾馆S走到宾馆T,速度为v

【输出格式】

对于每个T,输出一行,表示顾客的碰面次数。

【样例输入】

1

3

1 2 1

2 3 1

3

1 3 2

3 1 1

1 2 3

1

0

【样例输出】

2

0

【数据规模】

1<=T<=20   1<=N<=10^5   0<=M<=10^3   1<=V<=10^6   1<=Z<=10^3


题解:

题意就是求两两树上路径是否能在相交路径上相遇

求相交路径自然就要求出最近公共祖先

╰( ̄▽ ̄)╭为了卡常数,使用O(1)求Lca的方法(当然,某位dalao用了O(log2(n))的树剖,并真的好像跑得确实稍微快那么一点~~~)

首先处理出树的欧拉序列(就是把每个点入栈和出栈记录下来,那么两个点的Lca就是它们组成的区间中深度最小的点)

用Rmq处理区间最值和对应的点就好啦

有了Lca,两个点的距离自然好求

那么我们就解决了问题的子问题的子问题的两个子问题啦

先考虑如何求出在一条路径上与某个点距离最近的点,记为Closest(a,b,c)

假设我们要求出(a,b)路径上的距离c最近的点

记x=Lca(a,b),y=Lca(c,a),z=Lca(c,b)

首先如果c不在x的子树内,由于树上最近路径唯一,x就是在(a,b)路径上与c最近的点

否则如果y不为x,这说明c和a同时属于x某个孩子的子树,那么y就是最近点,z同理

再否则说明a,b,c分属x三个孩子的子树,那么x还是最近点

至此我们解决了求路径上与点最近的点的问题

我们再来考虑如何求出两条路径的交这个子问题(对,没错,上面那个就是子问题的子问题,也是问题的子问题)

如果两条路径有交,那么第一条路径的两个点与第一条路径的两个最近点组成的路径必定与第二条路径的两个点与第一条路径的两个最近点组成的路径相等

有点点长(不是打错了(废话好多(自己吐槽是什么鬼))),冗长的自然语言啊

记两条路径为(a,b)和(c,d)

记abc为Close(a,b,c),其他同理

那么(abc,abd)=(cda,cdb)(这是无序的)

又一个问题解决了

最后考虑是否相遇

起点相同啊,没有相交路径啊,相交路径只有一个点啊,这些判一判就好啦

设两个人为x,y

设相交路径为u,v

设两条路径(两个人)的起点、终点为sx,tx,sy,ty

记Time(x,y)为x为起点,y为终点,以以x为起点的人的速度为速度所需的时间(再次重申没有打错)

求相遇当然要判断同向异向,判断的话考虑Closest(u,v,sx)是否等于Closest(u,v,sy),两个的含义分别是求两个点在相交路径上的起点,剩下的就显而易见了

为了方便,取u为x在(u,v)上的起点

异向的话只要满足一个在到达起点时另一个还未达到终点,那么它们必定相遇,判断就是Time(sx,u)<=Time(sy,u)且Time(sy,v)<=Time(sx,v)

同向的话只要满足先到达起点的后到达终点就行了,判断就看代码实现吧

求时间的话要用double啥的

由于我们只要求大小关系,交叉相乘即可

至此我们结束了整个问题(os:怎么这么长~~~~~~)

其实我是%了黄学长代码的<(* ̄▽ ̄*)/(那你还bb这么多)

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int logn = ;
const int maxn = ;
int lea[maxn][logn], dot[maxn][logn];
int num, pos[maxn], dfn[maxn], dep[maxn];
long long dis[maxn];
int tot, nex[maxn], fir[maxn], ver[maxn], val[maxn];
int powe[logn], loga[maxn];
int T;
int n, m;
int x, y, z;
int ans;
int s[maxn], t[maxn], vel[maxn];
struct couple
{
int x, y;
};
inline void Scan(int &x)
{
char c;
bool o = false;
while((c = getchar()) < '' || c > '')
if(c == '-') o = true;
x = c - '';
while((c = getchar()) >= '' && c <= '')
x = x * + c - '';
x = (o) ? -x : x;
}
inline void Clear()
{
tot = num = ans = ;
for(int i = ; i <= n; ++i) fir[i] = ;
}
inline void Ins(int x, int y, int z)
{
nex[++tot] = fir[x];
fir[x] = tot;
ver[tot] = y;
val[tot] = z;
}
inline void Table()
{
powe[] = ;
loga[] = ;
for(int i = ; i < logn; ++i) powe[i] = powe[i - ] << , loga[powe[i]] = ;
for(int i = ; i < maxn; ++i) loga[i] += loga[i - ];
}
inline void Rmq()
{
for(int i = ; i <= num; ++i)
{
dot[i][] = dfn[i];
lea[i][] = dep[dfn[i]];
}
for(int j = ; j <= loga[num] + ; ++j)
for(int i = ; i <= num; ++i)
{
int k = i + powe[j - ];
if(k >= num) continue;
if(lea[i][j - ] < lea[k][j - ])
{
lea[i][j] = lea[i][j - ];
dot[i][j] = dot[i][j - ];
}
else
{
lea[i][j] = lea[k][j - ];
dot[i][j] = dot[k][j - ];
}
}
}
inline int Lca(int x, int y)
{
x = pos[x], y = pos[y];
if(x > y) swap(x, y);
int len = loga[y - x + ];
int mid = y - powe[len] + ;
if(lea[x][len] < lea[mid][len]) return dot[x][len];
return dot[mid][len];
}
inline long long Dis(int x, int y)
{
return dis[x] + dis[y] - (dis[Lca(x, y)] << );
}
void Dfs(int u, int f)
{
pos[u] = ++num;
dfn[num] = u;
for(int i = fir[u]; i; i = nex[i])
{
int v = ver[i];
if(v == f) continue;
dep[v] = dep[u] + ;
dis[v] = dis[u] + val[i];
Dfs(v, u);
dfn[++num] = u;
}
}
inline int Close(int a, int b, int c)
{
int x = Lca(a, b);
if(x != Lca(x, c)) return x;
int y = Lca(a, c);
if(x != y) return y;
int z = Lca(b, c);
if(x != z) return z;
return x;
}
inline couple Path(int a, int b, int c, int d)
{
int abc = Close(a, b, c);
int abd = Close(a, b, d);
int cda = Close(c, d, a);
int cdb = Close(c, d, b);
if(abc > abd) swap(abc, abd);
if(cda > cdb) swap(cda, cdb);
if(abc == cda && abd == cdb) return (couple) {abc, abd};
return (couple) {-, -};
}
inline bool Meet(int x, int y)
{
if(s[x] == s[y]) return true;
couple z = Path(s[x], t[x], s[y], t[y]);
int u = z.x, v = z.y;
if(u < ) return false;
if(u == v) return Dis(s[x], u) * vel[y] == Dis(s[y], u) * vel[x];
if(Close(u, v, s[x]) == v) swap(u, v);
if(Close(u, v, s[x]) != Close(u, v, s[y]))
{
bool fa = Dis(s[x], u) * vel[y] <= Dis(s[y], u) * vel[x];
bool fb = Dis(s[x], v) * vel[y] >= Dis(s[y], v) * vel[x];
return fa && fb;
}
long long a = Dis(s[x], u) * vel[y];
long long b = Dis(s[y], u) * vel[x];
if(a == b) return true;
if(a > b) swap(x, y);
return Dis(s[x], v) * vel[y] >= Dis(s[y], v) * vel[x];
}
int main()
{
memset(lea, , sizeof(lea));
Table();
Scan(T);
while(T--)
{
Clear();
Scan(n);
for(int i = ; i < n; ++i)
{
Scan(x), Scan(y), Scan(z);
Ins(x, y, z);
Ins(y, x, z);
}
Dfs(, );
Rmq();
Scan(m);
for(int i = ; i <= m; ++i) Scan(s[i]), Scan(t[i]), Scan(vel[i]);
for(int i = ; i <= m; ++i)
for(int j = i + ; j <= m; ++j)
ans += Meet(i, j);
printf("%d\n", ans);
}
}

发展城市 BZOJ 3700的更多相关文章

  1. BZOJ3700: 发展城市

    BZOJ3700: 发展城市 https://lydsy.com/JudgeOnline/problem.php?id=3700 分析: 枚举两个人,先求链交,求到两个端点的时间. 链交求法:求两两\ ...

  2. 【BZOJ3700】发展城市 [LCA][RMQ]

    发展城市 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 众所周知,Hzwer学长是一名高富 ...

  3. BZOJ1906树上的蚂蚁&BZOJ3700发展城市——RMQ求LCA+树链的交

    题目描述 众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市. Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道.机智 ...

  4. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  5. 拓扑排序 --- hdu 4948 : Kingdom

    Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  6. [Arduino] 基于Xbee Pro和网络技术的智能公交系统设计

    转自:http://www.21ic.com/app/rf/201112/99474.htm 引言 公共交通具有个体交通无法比拟的强大优势,优先发展城市公共交通系统是解决大.中城市交通问题的最佳途径. ...

  7. 2015年iOS开发工程师前景分析

    "互联网+"概念的提出催生了大量互联网企业,越来越多的传统行业需要与互联网更深地渗透与融合.而在这股互联网化的浪潮中,行业却发现找不到优秀的互联网人才. 互联网企业数量持续增长,用 ...

  8. dsu on tree:关于一类无修改询问子树可合并问题

    dsu on tree:关于一类无修改询问子树可合并问题 开始学长讲课的时候听懂了但是后来忘掉了....最近又重新学了一遍 所谓\(dsu\ on\ tree\)就是处理本文标题:无修改询问子树可合并 ...

  9. Ming Yin(@kalasoo)在知乎的几个回答 : 观点犀利

    这篇文章汇总了掘金前站长Ming Yin(阴明)在知乎的几个犀利的观点,原文可访问zhihu.com/kalasoo 由@flightmakers转载(收藏)在此 你是否有个人网站.可否和大家分享一下 ...

随机推荐

  1. map最基本操作

    #include<iostream> #include<map> using namespace std; int main() { /*map<int,char> ...

  2. WPF中窗体在同一个位置实现不同页面切换

    要想在WPF窗体中实现不同页面切换,我们就需要用到ContentControl这个控件,这个控件的位置和大小就是你要显示页面的位置和大小. 下面举例说明: Xaml: <Grid> < ...

  3. maven项目jsp无法识别jstl的解决办法

    EL表达式无效是因为maven项目的jsp不识别jstl,只要在web-APP 标签中引入命名空间 xmlns="http://xmlns.jcp.org/xml/ns/javaee&quo ...

  4. python之文件读写操作(r/r+/rb/w/w+/wb/a/a+/ab)的作用

    'r':只读.该文件必须已存在. 'r+':可读可写.该文件必须已存在,写为追加在文件内容末尾. 'rb':表示以二进制方式读取文件.该文件必须已存在. 'w':只写.打开即默认创建一个新文件,如果文 ...

  5. netfilter 和 iptables

    http://blog.chinaunix.net/uid/23069658/cid--1-list-4.html 洞悉linux下的Netfilter&iptables  系列,有一到十六, ...

  6. GIMP的Path用法,快速选区

    1/很多的快捷键,不多就Shift Ctrl Alt可以自由选择,这里自己多试几次可以熟练掌握吧. 2/快速选区作为Path,这里颜色要纯一点好:Selection to Path Step1:选择F ...

  7. rz

    Linux系统简单易用的上传下载命令rz和sz sudo yum install lrzsz -y 上传:rz 下载:sz

  8. if else elif 用法和区别

    1.If语句:“如果条件为真,执行子句中的代码."始终包含以下部分: if关键字: 条件(即求值为True或False的表达式): 冒号: 在下一行开始,缩进的代码块(称为if子句) 例如: ...

  9. PAT Basic 1029

    1029 旧键盘 旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及实际被输入的文字,请你列出肯定坏掉的那些键. 输入格式: 输入在2行中分别给出应该输 ...

  10. linux python 安装 pip出现 No module named 'setuptools'

    1.下载pip wget --no-check-certificate https://pypi.python.org/packages/source/p/pip/pip-8.0.2.tar.gz#m ...