题目描述
比特山是比特镇的飙车圣地。在比特山上一共有n 个广场,编号依次为1 到n,这些广场之间通过n-1 条双向车道直接或间接地连接在一起,形成了一棵树的结构。
因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字li、 ri 量化地表示一条车道的承受区间,只有当汽车以不小于li 且不大于ri 的速度经过这条车道时,才不会对路面造成伤害。Byteasar 最近新买了一辆跑车,他想在比特山飙一次车。Byteasar 计划选择两个不同的点S、 T,然后在它们树上的最短路径上行驶,且不对上面任意一条车道造成伤害。
Byteasar 不喜欢改变速度,所以他会告诉你他的车速。为了挑选出最合适的车速,Byteasar 一共会向你询问m 次。请帮助他找到一条合法的道路,使得路径上经过的车道数尽可能多。
输入
第一行包含两个正整数n,m,表示广场的总数和询问的总数。
接下来n-1 行,每行四个正整数ui, vi, li, ri,表示一条连接ui 和vi 的双向车道,且承受区间为[li,ri]。接下来m 行,每行一个正整数qi,分别表示每个询问的车速。
输出
输出m 行,每行一个整数,其中第i 行输出车速为qi 时的最长路径的长度,如果找不到合法的路径则输出0。
线段树优化套直径合并。
对于有效区间为[L,R]的修改的题目,可以考虑把修改放到线段树上当做永久化标记,然后对线段树进行DFS,利用恢复操作,充分利用每一层的答案。 至于直径合并,自己想想就行。由于恢复操作,并查集要用按高度排序(比按大小排序居然快了300ms)
AC Code:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#include<cmath>
#define maxn 70005
#define lim 18
#define lc now<<1
#define rc now<<1|1
using namespace std;
namespace IO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define ll long long
//fread->read
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
//{printf("IO error!\n");system("pause");for (;;);exit(0);}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(double &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (ch=='.'){
double tmp=1; ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
}
if (sign)x=-x;
}
inline void read(char *s){
char ch=nc();
for (;blank(ch);ch=nc());
if (IOerror)return;
for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
*s=0;
}
inline void read(char &c){
for (c=nc();blank(c);c=nc());
if (IOerror){c=-1;return;}
}
//fwrite->write
struct Ostream_fwrite{
char *buf,*p1,*pend;
Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
void out(char ch){
if (p1==pend){
fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
}
*p1++=ch;
}
void print(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(int x){
static char s[15],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1);
}
void println(ll x){
static char s[25],*s1;s1=s;
if (!x)*s1++='0';if (x<0)out('-'),x=-x;
while(x)*s1++=x%10+'0',x/=10;
while(s1--!=s)out(*s1); out('\n');
}
void print(double x,int y){
static ll mul[]={1,10,100,1000,10000,100000,1000000,10000000,100000000,
1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL};
if (x<-1e-12)out('-'),x=-x;x*=mul[y];
ll x1=(ll)floor(x); if (x-floor(x)>=0.5)++x1;
ll x2=x1/mul[y],x3=x1-x2*mul[y]; print(x2);
if (y>0){out('.'); for (size_t i=1;i<y&&x3*mul[i]<mul[y];out('0'),++i); print(x3);}
}
void println(double x,int y){print(x,y);out('\n');}
void print(char *s){while (*s)out(*s++);}
void println(char *s){while (*s)out(*s++);out('\n');}
void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
~Ostream_fwrite(){flush();}
}Ostream;
inline void print(int x){Ostream.print(x);}
inline void println(int x){Ostream.println(x);}
inline void print(char x){Ostream.out(x);}
inline void println(char x){Ostream.out(x);Ostream.out('\n');}
inline void print(ll x){Ostream.print(x);}
inline void println(ll x){Ostream.println(x);}
inline void print(double x,int y){Ostream.print(x,y);}
inline void println(double x,int y){Ostream.println(x,y);}
inline void print(char *s){Ostream.print(s);}
inline void println(char *s){Ostream.println(s);}
inline void println(){Ostream.out('\n');}
inline void flush(){Ostream.flush();}
#undef ll
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace IO;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
inline void Node(const int &u,const int &v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int n,m;
int x[maxn],y[maxn],rec[maxn][7];
vector<int>vec[maxn*10];
// remember to check how much MB I used;
// 23 MB perfect
void insert(int now,int l,int r,int ql,int qr,int id)
{
if(ql > r || qr < l) return;
if(ql <= l && r <= qr){vec[now].push_back(id);return;}
int mid =(l+r)>>1;
insert(lc,l,mid,ql,qr,id),insert(rc,mid+1,r,ql,qr,id);
}
int ans[maxn],siz[maxn],loc[2][maxn],dis[maxn];
int Min[lim][maxn<<1],tot,pos[maxn],dep[maxn],F[maxn],lg[maxn<<1];
inline int Find(int now){
return !F[now] ? now : Find(F[now]);
}
void dfs(int now,int ff)
{
dep[now] = dep[ff] + 1;
Min[0][pos[now] = ++tot] = now;
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff)
{
dfs(to[i],now);
Min[0][++tot] = now;
}
}
inline int Lca(int u,int v)
{
u = pos[u] , v = pos[v];
if(u > v) swap(u,v);
int tmp = lg[v - u + 1];
return dep[Min[tmp][u]] < dep[Min[tmp][v-(1<<tmp)+1]] ? Min[tmp][u] : Min[tmp][v-(1<<tmp)+1];
}
inline int Dis(int u,int v)
{
int lca = Lca(u,v);
return dep[u] + dep[v] - 2 * dep[lca];
}
int Maxlen = 0;
inline void add(int id)
{
int u = Find(x[id]) , v = Find(y[id]);
int a[2]={Dis(x[id],loc[0][u]),Dis(x[id],loc[1][u])},b[2]={Dis(y[id],loc[0][v]),Dis(y[id],loc[1][v])};
int ndis=0,tmp=(a[a[1] > a[0]] + b[b[1] > b[0]] + 1),LC[2];
if(dis[u] > dis[v])
{
if(dis[u] > tmp) ndis = dis[u] , LC[0] = loc[0][u] , LC[1] = loc[1][u];
else ndis = tmp , LC[0] = loc[a[1] > a[0]][u] , LC[1] = loc[b[1] > b[0]][v];
}
else
{
if(dis[v] > tmp) ndis = dis[v] , LC[0] = loc[0][v] , LC[1] = loc[1][v];
else ndis = tmp , LC[0] = loc[a[1] > a[0]][u] , LC[1] = loc[b[1] > b[0]][v];
}
if(siz[u] > siz[v]) swap(u,v);
rec[id][0] = u , F[u] = v ;
rec[id][5] = Maxlen;
Maxlen = max(Maxlen,ndis);
rec[id][1] = v , rec[id][2] = dis[v] , dis[v] = ndis;
rec[id][3] = loc[0][v] , rec[id][4] = loc[1][v];
loc[0][v] = LC[0] , loc[1][v] = LC[1];
rec[id][6] = siz[v];
siz[v] = (siz[u] == siz[v] ? siz[v]+1 : siz[v]);
}
inline void recover(int id)
{
int u = rec[id][0] , v = rec[id][1];
Maxlen = rec[id][5];
F[u] = 0 , dis[v] = rec[id][2];
loc[0][v] = rec[id][3] , loc[1][v] = rec[id][4];
siz[v] = rec[id][6];
}
void solve(int now,int l,int r)
{
if(l>r) return;
for(int i=0,siz=vec[now].size();i<siz;i++)
add(vec[now][i]);
if(l == r){
ans[l] = Maxlen;
for(int siz=vec[now].size(),i=siz-1;i>=0;i--)
recover(vec[now][i]);
return;
}
int mid = (l + r) >> 1;
solve(lc,l , mid);
solve(rc,mid+1,r);
for(int siz=vec[now].size(),i=siz-1;i>=0;i--)
recover(vec[now][i]);
}
int main()
{
read(n),read(m);
for(int i=1,l,r;i<n;i++)
{
read(x[i]),read(y[i]),read(l),read(r);
Node(x[i],y[i]),Node(y[i],x[i]);
insert(1,1,n,l,r,i);
}
for(int i=1;i<=n;i++) loc[0][i] = loc[1][i] = i , siz[i] = 1;
dfs(1,0);
for(int i=1,LG=-1,sum=1;i<=tot;lg[i] = LG,i++) if(sum == i) LG++ , sum <<=1;
for(int j=1;j<lim;j++)
for(register int i=1;i<=tot;i++)
if(i + (1<<j-1) <= tot)
Min[j][i] = dep[Min[j-1][i]] < dep[Min[j-1][i + (1<<j-1)]] ? Min[j-1][i] : Min[j-1][i+(1<<j-1)];
solve(1,1,n);
for(int tmp;m--;)
read(tmp),println(ans[tmp]);
}