越野赛车问题
题目描述
小 H 是一位优秀的越野赛车女选手。现在她准备在 A 山上进行赛车训练。
A 山上一共有 n 个广场,编号依次为 1 到 n,这些广场之间通过 n−1 条双向车道直接或间接地连接在一起。对于每条车道 i,可以用四个正整数 ui,vi,li,ri 描述,表示车道连接广场 ui 和 vi,其速度承受区间为 [li,ri],即汽车必须以不小于 li 且不大于 ri 的速度经过车道 i。
小 H 计划进行 m 次训练,每次她需要选择 A 山上的一条简单路径,然后在这条路径上行驶。但小 H 不喜欢改变速度,所以每次训练时的车速都是固定的。现在小 H 告诉你她在 m 次训练中计划使用的车速,请帮助她对于每次训练,找到一条合法的路径(车速在所有车道的速度承受区间的交集内),使得路径上经过的车道数最大。
输入格式
输入文件的第一行包含两个正整数 n,m,表示广场数和训练次数。接下来 n−1 行,每行四个正整数 ui,vi,li,ri(≤n),描述所有车道。最后 m 行,每行一个正整数 v(≤n),表示小 H 每次训练时使用的车速。
输出格式
输出 m 行,将每次训练时的行驶路径经过的最大车道数输出到文件中。
输入输出样例
输入 #1
5 3
3 2 2 4
1 5 2 5
4 5 2 2
1 2 3 5
1
2
3
输出 #1
0
2
3
数据点 n m 约定
1 =5 =5
2 =20 =20
3 =50000 =50000 li=1,ui=i,vi=i+1
4 =70000 =70000 li=1,ui=i,vi=i+1
5 =50000 =50000 ui=i,vi=i+1
6 =70000 =70000 ui=i,vi=i+1
7 =50000 =50000 li=1
8 =70000 =70000 li=1
9 =50000 =50000
10 =70000 =70000
按长度线段树分治,可撤销并查集维护连通块内直径。
code:
#include<bits/stdc++.h>
using namespace std;
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
const int maxn=70010;
int n,m;
int ans[maxn];
struct Edge{int u,v,l,r;}E[maxn];
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
int cnt_edge,tim;
int head[maxn],dep[maxn],pos[maxn],lg[maxn*2];
int f[maxn*2][20];
struct edge{int to,nxt;}e[maxn<<1];
inline void add_edge(int u,int v)
{
e[++cnt_edge]=(edge){v,head[u]};
head[u]=cnt_edge;
}
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
f[++tim][0]=x,pos[x]=tim;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa)continue;
dfs(y,x);
f[++tim][0]=x;
}
}
inline int lca(int x,int y)
{
if(pos[x]>pos[y])swap(x,y);
x=pos[x],y=pos[y];
int t=lg[y-x+1];
return dep[f[x][t]]<dep[f[y-(1<<t)+1][t]]?f[x][t]:f[y-(1<<t)+1][t];
}
inline int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
vector<int>seg[maxn<<2];
void insert(int p,int l,int r,int ql,int qr,int id)
{
if(l>=ql&&r<=qr){seg[p].push_back(id);return;}
int mid=(l+r)>>1;
if(ql<=mid)insert(ls(p),l,mid,ql,qr,id);
if(qr>mid)insert(rs(p),mid+1,r,ql,qr,id);
}
#define pii pair<int,int>
#define mkp make_pair
#define sec second
#define fir first
int top;
int fa[maxn],size[maxn];
pii pt[maxn];
struct node
{
int x,y;
pii pt;
}sta[maxn<<2];
int find(int x){return fa[x]==x?x:find(fa[x]);}
inline void del(node a)
{
int x=a.x,y=a.y;pii p=a.pt;
fa[y]=y,size[x]-=size[y];
pt[x]=p;
}
void solve(int p,int l,int r,int nowans)
{
int tmp=top;
for(unsigned int i=0;i<seg[p].size();i++)
{
int id=seg[p][i];
int x=find(E[id].u),y=find(E[id].v);
if(size[x]<size[y])swap(x,y);
sta[++top]=(node){x,y,pt[x]};
int maxx=dis(pt[x].fir,pt[x].sec);pii now=pt[x];
if(dis(pt[y].fir,pt[y].sec)>maxx)maxx=dis(pt[y].fir,pt[y].sec),now=pt[y];
if(dis(pt[x].fir,pt[y].fir)>maxx)maxx=dis(pt[x].fir,pt[y].fir),now=mkp(pt[x].fir,pt[y].fir);
if(dis(pt[x].fir,pt[y].sec)>maxx)maxx=dis(pt[x].fir,pt[y].sec),now=mkp(pt[x].fir,pt[y].sec);
if(dis(pt[x].sec,pt[y].fir)>maxx)maxx=dis(pt[x].sec,pt[y].fir),now=mkp(pt[x].sec,pt[y].fir);
if(dis(pt[x].sec,pt[y].sec)>maxx)maxx=dis(pt[x].sec,pt[y].sec),now=mkp(pt[x].sec,pt[y].sec);
pt[x]=now;fa[y]=x,size[x]+=size[y];
nowans=max(nowans,maxx);
}
if(l==r)ans[l]=nowans;
else
{
int mid=(l+r)>>1;
solve(ls(p),l,mid,nowans);solve(rs(p),mid+1,r,nowans);
}
while(top>tmp)del(sta[top]),top--;
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;i++)E[i].u=read(),E[i].v=read(),E[i].l=read(),E[i].r=read();
for(int i=1;i<n;i++)add_edge(E[i].u,E[i].v),add_edge(E[i].v,E[i].u);
dfs(1,0);
lg[0]=-1;
for(int i=1;i<=tim;i++)lg[i]=lg[i>>1]+1;
for(int j=1;j<=18;j++)
for(int i=1;i+(1<<j)-1<=tim;i++)
f[i][j]=dep[f[i][j-1]]<dep[f[i+(1<<j-1)][j-1]]?f[i][j-1]:f[i+(1<<j-1)][j-1];
for(int i=1;i<n;i++)insert(1,1,n,E[i].l,E[i].r,i);
for(int i=1;i<=n;i++)fa[i]=i,size[i]=1,pt[i]=mkp(i,i);
solve(1,1,n,0);
while(m--)printf("%d\n",ans[read()]);
return 0;
}