【百度之星初赛A】路径交

Problem Description

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

Input

第一行一个数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

Output

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

Sample Input

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

Sample Output

5

题解:看到题的第一反应就是线段树,然后在区间合并的时候求一下两个路径的交即可,现在我们只需要快速求出两个路径的交即可。

设两条路径分别为a1-b1,a2-b2,它们的lca是c1,c2,求出a1,b1-a2,b2两两之间的lca,设分别为d1,d2,d3,d4,假设dep[d1]<=dep[d2]<=dep[d3]<=dep[d4],dep[c1]<=dep[c2]。那么如果两条路径有交,当且仅当dep[d1]>=dep[c1]且dep[d4]>=dep[d3]>=dep[c2](自己画画就知道了)。并且如果有交,那么交一定是d3-d4。

如果用RMQ求LCA,则时间复杂度为nlogn。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=500010;
typedef long long ll;
struct path
{
int a,b,c;
path(){}
path(int A,int B,int C) {a=A,b=B,c=C;}
}p[maxn],s[maxn<<2];
int n,m,q,cnt;
int mn[20][maxn<<1],Log[maxn<<1],pos[maxn],dep[maxn],fa[maxn];
int head[maxn],nxt[maxn<<1],val[maxn<<1],to[maxn<<1];
int cs[10];
ll len[maxn];
int MN(int a,int b)
{
return dep[a]<dep[b]?a:b;
}
int lca(int a,int b)
{
int x=pos[a],y=pos[b];
if(x>y) swap(x,y);
int k=Log[y-x+1];
return MN(mn[k][x],mn[k][y-(1<<k)+1]);
}
bool cmp(int a,int b)
{
return dep[a]<dep[b];
}
path mix(path x,path y)
{
if(!x.c||!y.c) return path(0,0,0);
cs[1]=lca(x.a,y.a),cs[2]=lca(x.a,y.b),cs[3]=lca(x.b,y.a),cs[4]=lca(x.b,y.b);
sort(cs+1,cs+5,cmp);
int md=max(dep[x.c],dep[y.c]),nd=min(dep[x.c],dep[y.c]);
if(dep[cs[1]]<nd||dep[cs[3]]<md) return path(0,0,0);
else return path(cs[3],cs[4],lca(cs[3],cs[4]));
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,nxt[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
pos[x]=++pos[0],mn[0][pos[0]]=x;
for(int i=head[x];i!=-1;i=nxt[i])
{
if(to[i]!=fa[x])
{
fa[to[i]]=x,dep[to[i]]=dep[x]+1,len[to[i]]=len[x]+val[i],dfs(to[i]);
mn[0][++pos[0]]=x;
}
}
}
void build(int l,int r,int x)
{
if(l==r)
{
s[x]=p[l];
return ;
}
int mid=l+r>>1;
build(l,mid,lson),build(mid+1,r,rson);
s[x]=mix(s[lson],s[rson]);
}
path query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
int mid=l+r>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return mix(query(l,mid,lson,a,b),query(mid+1,r,rson,a,b));
}
int main()
{
n=rd();
int i,j,a,b,c;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
dep[1]=1,dfs(1);
for(i=2;i<=2*n-1;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=2*n-1;j++) for(i=1;i+(1<<j)-1<=2*n-1;i++) mn[j][i]=MN(mn[j-1][i],mn[j-1][i+(1<<j-1)]);
m=rd();
for(i=1;i<=m;i++) p[i].a=rd(),p[i].b=rd(),p[i].c=lca(p[i].a,p[i].b);
build(1,m,1);
q=rd();
for(i=1;i<=q;i++)
{
a=rd(),b=rd();
path ans=query(1,m,1,a,b);
printf("%lld\n",len[ans.a]+len[ans.b]-2*len[ans.c]);
}
return 0;
}

【百度之星初赛A】路径交 LCA+线段树的更多相关文章

  1. 2016百度之星 初赛2A ABEF

    只做了1001 1002 1005 1006.剩下2题可能以后补? http://acm.hdu.edu.cn/search.php?field=problem&key=2016%22%B0% ...

  2. HDU 5690:2016"百度之星" - 初赛 All X

    原文链接:https://www.dreamwings.cn/hdu5690/2657.html All X Time Limit: 2000/1000 MS (Java/Others)    Mem ...

  3. 2016"百度之星" - 初赛(Astar Round2A)HDU 5695 拓扑排序+优先队列

    Gym Class Time Limit: 6000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  4. 数学 2015百度之星初赛2 HDOJ 5255 魔法因子

    题目传送门 /* 数学:不会写,学习一下这种解题方式:) 思路:设符合条件的数的最高位是h,最低位是l,中间不变的部分为mid,由题意可得到下面的公式(这里对X乘上1e6用a表示,b表示1e6) (h ...

  5. LIS 2015百度之星初赛2 HDOJ 5256 序列变换

    题目传送门 题意:中文题面 分析:LIS(非严格):首先我想到了LIS,然而总觉得有点不对:每个数先减去它的下标,防止下面的情况发生:(转载)加入序列是1,2,2,2,3,这样求上升子序列是3,也就是 ...

  6. Kruskal 2015百度之星初赛2 HDOJ 5253 连接的管道

    题目传送门 /* 最小生成树(Kruskal):以权值为头,带入两个端点,自然的排序;感觉结构体的并查集很好看 注意:题目老头要的是两个农田的高度差,中文水平不好,题意理解成和平均值的高度差! */ ...

  7. BFS 2015百度之星初赛2 HDOJ 5254 棋盘占领

    题目传送门 /* BFS:先把1的入队,每个1和它相邻的组合后看看能不能使0变1,若有则添加入队,change函数返回改变了多少个0 注意:结果还要加上原来占领的 */ #include <cs ...

  8. 二分搜索 2015百度之星初赛1 HDOJ 5248 序列变换

    题目传送门 /* 二分搜索:在0-1e6的范围找到最小的max (ai - bi),也就是使得p + 1 <= a[i] + c or a[i] - c 比赛时以为是贪心,榨干智商也想不出来:( ...

  9. 二分查找 2015百度之星初赛1 HDOJ 5246 超级赛亚ACMer

    题目传送门 /* 二分找到不大于m的最大的数,记做p,只要a[p] + k <= a[p+1]就继续 注意:特判一下当没有比m小的数的情况:) */ #include <cstdio> ...

随机推荐

  1. Python入门--18--异常与try,except语句

    Python标准异常总结 AssertionError 断言语句(assert)失败 AttributeError 尝试访问未知的对象属性 EOFError 用户输入文件末尾标志EOF(Ctrl+d) ...

  2. dedecms--数据库

    最近在用dedecms做项目,dedecms里面有数据库操作类,其实这个在实际项目中用起来还是很方便的. 1:引入common.inc.php文件 require_once (dirname(__FI ...

  3. spring boot--日志、开发和生产环境切换、自定义配置(环境变量)

    Spring Boot日志常用配置: # 日志输出的地址:Spring Boot默认并没有进行文件输出,只在控制台中进行了打印 logging.file=/home/zhou # 日志级别 debug ...

  4. va_list 简介

    原文:http://blog.sina.com.cn/s/blog_590be5290100qhxr.html va_list是一个宏,由va_start和va_end界定. typedef char ...

  5. HDU4372 Buildings

    @(HDU)[Stirling數, 排列組合] Problem Description There are N buildings standing in a straight line in the ...

  6. 邁向IT專家成功之路的三十則鐵律 鐵律十:IT人思維之道-跳脫框架

    莊子的哲學思想歸本於老子,他認為人要解脫束縛必須做到不從任何的角度與任何的時間來看待事物,而是必須與天地同體,然而也唯有如此才能看清宇宙間萬事萬理的真諦.無論是莊子還是老子,他們畢竟是中國古代的聖賢, ...

  7. openfire Android学习(一)----实现用户注册、登录、修改密码和注销等

    以前学习过用Scoket 建立聊天,简单的建立聊天是没问题的,但如果要实现多人复杂的聊天,后台服务器代码就比较复杂,对于我这新手来讲就比较难了.后来在网上看到用openfire做服务器,利用强大的Sm ...

  8. OpenGL step to step(1)

    在窗体上绘制一个矩形,just a demo #include <GLUT/GLUT.h> void init() { glClearColor(0.0,0.0,0.0,0.0); glS ...

  9. 最全的HTTP头部信息分析

    HTTP 头部解释 1. Accept:告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type. 2. Accept-Chars ...

  10. [Maven实战](9)传递性依赖

    了解Spring的朋友都知道.创建一个Spring Framework项目都须要依赖什么样的Jar包.假设不使用Maven,那么在项目中就须要手动下载相关的依赖.因为Spring Framework又 ...