【百度之星初赛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;
}

最新文章

  1. NSArray与NSMutableArray 数组与可变数组
  2. Google推荐的图片加载库Glide介绍
  3. win10里安装.net3.5
  4. 使用std::function 把类成员函数指针转换为普通函数指针
  5. 第三周作业、实时操作系统&#181;C/OS介绍及其它内容
  6. 三、使用Maven构建简单的java项目
  7. React 学习资源分享 菜鸟刚学5天 博客写的不多 不懂写博客的套路
  8. A20 GPIO中断类型差别结果迥异的问题思考
  9. L1-8 矩阵A乘以B (15 分)
  10. Checked Uncheckd异常
  11. [Python] Python基础字符串
  12. FFMPEG指令
  13. SpringBoot集成SpringCloud
  14. 【正则表达式】使用正则表达式的group,查找出String中的参数值
  15. [转帖 cnblog 的news ]技术实力超群的Netflix,为何没有CTO
  16. poj1976
  17. windows平台下nginx+PHP环境安装
  18. angular的require模块的使用($requireProvider的作用)
  19. Linux操作命令(四)
  20. 【Machine Learning 学习笔记】OSX Octave 输出图像问题

热门文章

  1. DispatcherServlet与ContextLoaderListener的对比
  2. jQuery控件之分页控件-- kkpager v1.3使用简介
  3. 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)
  4. math对象的方法
  5. 转 C++构造函数、析构函数、虚函数之间的关系
  6. AC日记——图灵机游戏 codevs 2292
  7. AC日记——Weird Rounding Codeforces 779b
  8. ui develop
  9. python设置utf-8为默认编码
  10. c++ concurrency serial 1: introduction