问题描述

给定一棵n个点的树,以及m条路径,每次询问第L条到第R条路径的交集部分的长度(如果一条边同时出现在2条路径上,那么它属于路径的交集)。

输入格式

第一行一个数n(n<=500,000)

接下来n-1行,每行三个数x,y,z,表示一条从x到y并且长度为z的边

第n+1行一个数m(m<=500,000)

接下来m行,每行两个数u,v,表示一条从u到v的路径

接下来一行一个数Q,表示询问次数(Q<=500,000)

接下来Q行,每行两个数L和R

输出格式

Q行,每行一个数表示答案

样例输入

4

1 2 5

2 3 2

1 4 3

2

1 2

3 4

1

1 2

样例输出

5

解析

按照常规思想,这也许可以通过一些树上路径相关的数据结构来完成。但是实现起来有很大的困难。

看到询问的方式,与线段树区间询问的类型很相似。不妨也用类似的方法,用线段树维护路径的交集。具体维护起来可以通过维护交集路径的两个端点,加上一些分类讨论完成。为了保证复杂度是\(O(nlogn)\)的,需要用ST表实现最近公共祖先。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define N 500002
using namespace std;
const int inf=1<<30;
struct path{
int u,v,dis;
}a[N],t[N*4];
int head[N],ver[N*2],nxt[N*2],edge[N*2],l;
int n,m,q,i,st[N][30],dep[N],dis[N],in[N],s[N],top;
int read()
{
char c=getchar();
int w=0;
while(c<'0'||c>'9') c=getchar();
while(c<='9'&&c>='0'){
w=w*10+c-'0';
c=getchar();
}
return w;
}
void insert(int x,int y,int z)
{
l++;
ver[l]=y;
edge[l]=z;
nxt[l]=head[x];
head[x]=l;
}
void dfs(int x,int pre)
{
s[++top]=x;
dep[top]=dep[in[pre]]+1;
in[x]=top;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=pre){
dis[y]=dis[x]+edge[i];
dfs(y,x);
s[++top]=x,dep[top]=dep[in[x]];
}
}
}
int get(int x,int y)
{
if(dep[x]>dep[y]) return y;
return x;
}
void init()
{
dfs(1,0);
for(int i=1;i<=top;i++) st[i][0]=i;
for(int j=0;(1<<(j+1))<=top;j++){
for(int i=1;i+(1<<(j+1))-1<=top;i++) st[i][j+1]=get(st[i][j],st[i+(1<<j)][j]);
}
}
int LCA(int u,int v)
{
int l=in[u],r=in[v];
if(l>r) swap(l,r);
int k=log2(1.0*(r-l+1));
return s[get(st[l][k],st[r-(1<<k)+1][k])];
}
int dist(int u,int v)
{
return dis[u]+dis[v]-2*dis[LCA(u,v)];
}
int my_comp(const int &x,const int &y)
{
return dep[in[x]]>dep[in[y]];
}
path update(path x,path y)
{
if(x.dis==inf) return y;
if(y.dis==inf) return x;
if(x.u==y.u&&x.v==y.v) return x;
if(x.dis==0||y.dis==0) return (path){0,0,0};
int a[4];
a[0]=LCA(x.u,y.u);
a[1]=LCA(x.u,y.v);
a[2]=LCA(x.v,y.u);
a[3]=LCA(x.v,y.v);
sort(a,a+4,my_comp);
int p1=a[0],p2=a[1];
if(p1==p2&&((dep[in[p1]]<dep[in[LCA(x.u,x.v)]])||(dep[in[p2]]<dep[in[LCA(y.u,y.v)]]))) return (path){0,0,0};
return (path){p1,p2,dist(p1,p2)};
}
void build(int p,int l,int r)
{
if(l==r){
t[p].u=a[l].u,t[p].v=a[l].v;
t[p].dis=dist(t[p].u,t[p].v);
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p]=update(t[p*2],t[p*2+1]);
}
path ask(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return t[p];
int mid=(l+r)/2;
path ansl=(path){0,0,inf},ansr=(path){0,0,inf};
if(ql<=mid) ansl=ask(p*2,l,mid,ql,qr);
if(qr>mid) ansr=ask(p*2+1,mid+1,r,ql,qr);
return update(ansl,ansr);
}
int main()
{
n=read();
for(i=1;i<n;i++){
int u=read(),v=read(),w=read();
insert(u,v,w);
insert(v,u,w);
}
init();
m=read();
for(i=1;i<=m;i++) a[i].u=read(),a[i].v=read();
build(1,1,m);
q=read();
for(i=1;i<=q;i++){
int l=read(),r=read();
path ans=ask(1,1,m,l,r);
printf("%d\n",ans.dis);
}
return 0;
}

[51nod 1830] 路径交的更多相关文章

  1. hihocoder[Offer收割]编程练习赛19 D 相交的铁路线(树上路径交)

    傻逼题... 裸的树上路径交 两条树上的路径$[a,b]$和$[c,d]$有交,则有$lca(a,b)$在$[c,d]$上或$lca(c,d)$在$[a,b]$上. 其实只要深度大的$lca$在另一条 ...

  2. hdu 6010 路径交

    hdu 6010 路径交(lca + 线段树) 题意: 给出一棵大小为\(n\)的树和\(m\)条路径,求第\(L\)条路径到第\(R\)条路径的交的路径的长度 思路: 本题的关键就是求路径交 假设存 ...

  3. 【百度之星初赛A】路径交 LCA+线段树

    [百度之星初赛A]路径交 Problem Description 给定一棵n个点的树,以及m条路径,每次询问第L条到第R条路径的交集部分的长度(如果一条边同时出现在2条路径上,那么它属于路径的交集). ...

  4. hdu6110:路径交

    $n \leq 500000$的树给$m \leq 500000$个路径,$q \leq 500000$个询问每次问一个区间的路径交. 路径交口诀:(前方高能) 判有交,此链有彼祖: 取其交,最深两两 ...

  5. 2017"百度之星"程序设计大赛 - 初赛(A) [ hdu 6108 小C的倍数问题 ] [ hdu 6109 数据分割 ] [ hdu 6110 路径交 ] [ hdu 6112 今夕何夕 ] [ hdu 6113 度度熊的01世界 ]

    这套题体验极差. PROBLEM 1001 - 小C的倍数问题 题 OvO http://acm.hdu.edu.cn/showproblem.php?pid=6108 (2017"百度之星 ...

  6. 51nod 1443 路径和树(最短路)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1443 1443 路径和树 题目来源: CodeForces ...

  7. 【HDU】6110 路径交(2017百度之星) 线段树+RMQ-LCA+树链的交

    [题目]2017"百度之星"程序设计大赛 - 初赛(A) [题意]给定n个点的带边权树,m条编号1~m的路径,Q次询问编号区间[L,R]所有链的交集的长度.n<=500000 ...

  8. 51Nod 1967 路径定向 —— 欧拉回路

    题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1967 显然是欧拉回路问题,度数为奇数的点之间连边,跑欧拉回路就可以 ...

  9. 51nod 1443 路径和树(最短路树)

    题目链接:路径和树 题意:给定无向带权连通图,求从u开始边权和最小的最短路树,输出最小边权和. 题解:构造出最短路树,把存留下来的边权全部加起来.(跑dijkstra的时候松弛加上$ < $变成 ...

随机推荐

  1. java:struts框架4(Ajax)

    1.Ajax: 先导入jar包: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!D ...

  2. 错误:expected initializer before "***"

    今天写了一个程序,编译时报了一个错误:expected initializer before "***"报错的语句只是程序开头的一个变量定义语句,怎么会有这样的错误呢,琢磨了半天也 ...

  3. navicat 系列软件一点击菜单栏就闪退

    现象:安装多个版本都出现了闪退的现象 解决方案:后来发现,原来是启动了有道词典屏幕取词才会出现这种现象,关了有道就没事.

  4. Postman接口测试动态传参——动态获取token值

    上午刚学会jmeter动态传参,下午研究了下postman也知道怎么动态获取token了. 主要就是第1行和第2行代码,第3行加上是希望Test Results有个返回值,如果不加第3行运行成功后也看 ...

  5. Egret入门学习日记 --- 第五篇(书中 3.5节 内容)

    第五篇(书中 3.5节 内容) 今天得把昨天的问题解决了才行. 去了Q群,碰到一位大大,他给我解惑了.Thanks♪(・ω・)ノ 这是我之前按照书上写的方式写的,并没有效果. 然后大大给我解答了: 后 ...

  6. python 并发编程 多线程 多线程实现并发的套接字通信

    进程内会生成一个主线程,让主线程执行server函数,server函数核心是accept(),让主线程干accept的工作, 建立连接,每建立一个连接应该执行通信函数 每建立一个连接就是生成一个子线程 ...

  7. property可以声明得位置

    property可以声明的位置有4处 1 @interface处 2 扩展处 3 protocol处 4 分类处 其中分类处的property不会合成实例变量,并且编译器也不会自动合成实例变量

  8. Radio Button误区

    在同一个父容器下,Radio Button控件默认只能选择一个,所以无需多余代码管控 如果将Radio Button的多个子对象存入NSArray列表,发现长度为0(巨坑),因此通过列表对其初始化不可 ...

  9. Gogs官方帮助文档

    环境要求 数据库(选择以下一项): MySQL:版本 >= 5.7 PostgreSQL MSSQL TiDB(实验性支持,使用 MySQL 协议连接) 或者 什么都不安装 直接使用 SQLit ...

  10. 微信小程序里多出来的奇怪宽度

    最近在看微信小程序相关的东西,写页面的时候,因为一直以Iphone6作为标准调试(微信官方建议以Iphone6调试),下面以实际的案例讲解以rpx会引发的问题 wxml: <view class ...