题目大意
一颗树,每条边有边权[l,r]。
多次询问每次给定一个权值v,保留树上所有的边[l,r]使得l<=v且v<=r,然后求这片森林的最长简单路径长度。
经典CDQ
考虑分治算法
把每条边插入线段树区间中
然后一个权值的答案就是加入根到其对应叶子路径上经过的线段树节点上的所有边。
然后对线段树进行遍历,用并查集维护集合内的直径。因为要支持撤销,所以只能按秩合并不能路径压缩。
然后我跑的贼慢。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=70000+10,maxm=maxn*18*4+10,R=40*70000+10;
char buf[R+7],*ptr=buf-1;
int h[maxn],go[maxn<<1],next[maxn<<1],a[maxn*18][4];
int h2[maxn<<2],g2[maxm],n2[maxm];
int fa[maxn],rank[maxn],data[maxn][3];
int sta[maxn][6];//0~1 lianjie na liangge 2 rank[y] 3~4 data[y] 5 mx
bool ad[maxn];
int rmq[21][maxn<<1],ans[maxn],q[maxn],d[maxn],dfn[maxn<<1],fi[maxn],s[100];
int two[20];
bool pd[maxn];
int i,j,k,l,r,t,n,m,tot,top,pot,cnt,now,mx;
inline int read(){
int x=0,c=*++ptr;
while(c<48)c=*++ptr;
while(c>47)x=x*10+c-48,c=*++ptr;
return x;
}
inline void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
inline void dfs(int x,int y){
d[x]=d[y]+1;
dfn[++top]=x;
fi[x]=top;
int t=h[x];
while (t){
if (go[t]!=y){
dfs(go[t],x);
dfn[++top]=x;
}
t=next[t];
}
}
inline void add2(int x,int y){
g2[++cnt]=y;
n2[cnt]=h2[x];
h2[x]=cnt;
}
inline void newnode(int x){
++tot;
a[tot][0]=a[x][0];a[tot][1]=a[x][1];
a[tot][2]=a[x][2];a[tot][3]=a[x][3];
}
inline int getfa(int x){
while (fa[x]) x=fa[x];
return x;
}
inline int lca(int x,int y){
int l=fi[x],r=fi[y];
if (l>r) swap(l,r);
int z=floor(log(r-l+1)/log(2));
int j=rmq[z][l],k=rmq[z][r-two[z]+1];
if (d[dfn[j]]<d[dfn[k]]) return dfn[j];else return dfn[k];
}
inline int getdis(int x,int y){
int z=lca(x,y);
return d[x]+d[y]-(d[z]<<1);
}
inline void merge(int x,int y){
int a=getfa(x),b=getfa(y);
if (rank[a]>rank[b]) swap(a,b);
//if (a==b) return;
sta[++pot][0]=a;
sta[pot][1]=b;
sta[pot][2]=data[b][2];
sta[pot][3]=data[b][0];
sta[pot][4]=data[b][1];
sta[pot][5]=mx;
fa[a]=b;
if (rank[a]==rank[b]) rank[b]++,ad[pot]=1;else ad[pot]=0;
int i,j,ans1=data[b][0],ans2=data[b][1],l=data[b][2],t;
t=data[a][2];
if (t>l){
ans1=data[a][0];
ans2=data[a][1];
l=t;
}
t=getdis(data[a][0],data[b][0]);
if (t>l){
ans1=data[a][0];
ans2=data[b][0];
l=t;
}
t=getdis(data[a][0],data[b][1]);
if (t>l){
ans1=data[a][0];
ans2=data[b][1];
l=t;
}
t=getdis(data[a][1],data[b][0]);
if (t>l){
ans1=data[a][1];
ans2=data[b][0];
l=t;
}
t=getdis(data[a][1],data[b][1]);
if (t>l){
ans1=data[a][1];
ans2=data[b][1];
l=t;
}
if (l>mx) mx=l;
data[b][0]=ans1;data[b][1]=ans2;data[b][2]=l;
}
inline void re(int x){
int j=sta[x][0],k=sta[x][1];
fa[j]=0;
/*if (sta[x][2]!=rank[k])*/ if (ad[x]) rank[k]--;
data[k][2]=sta[x][2];
/*if (data[k][0]!=sta[x][3])*/ data[k][0]=sta[x][3];
/*if (data[k][1]!=sta[x][4])*/ data[k][1]=sta[x][4];
/*if (mx!=sta[x][5])*/ mx=sta[x][5];
}
inline void solve(int p,int l,int r){
int t=h2[p],i,j,k,now,tmp=pot,mid=(l+r)>>1;
while (t){
now=g2[t];
if (a[now][2]==l&&a[now][3]==r) merge(a[now][0],a[now][1]);
else if (a[now][3]<=mid) add2((p<<1),now);
else if (a[now][2]>mid) add2((p<<1)|1,now);
else{
newnode(now);
a[tot][2]=mid+1;
add2((p<<1)|1,tot);
a[now][3]=mid;
add2((p<<1),now);
}
t=n2[t];
}
if (l==r) ans[l]=mx;
else{
solve((p<<1),l,mid);
solve((p<<1)|1,mid+1,r);
}
while (pot>tmp){
re(pot);
pot--;
}
}
inline void write(int x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
s[++top]=x%10;
x/=10;
}
while (top){
putchar('0'+s[top]);
top--;
}
putchar('\n');
}
int main(){
freopen("speed.in","r",stdin);freopen("speed.out","w",stdout);
fread(buf,1,R,stdin);
n=read();m=read();
fo(i,1,n-1){
j=read();k=read();l=read();r=read();
add(j,k);add(k,j);
a[i][0]=j;
a[i][1]=k;
a[i][2]=l;
a[i][3]=r;
}
fo(i,1,m){
q[i]=read();
}
dfs(1,0);
fo(i,1,top) rmq[0][i]=i;
t=floor(log(top)/log(2));
two[0]=1;
fo(i,1,t) two[i]=(two[i-1]<<1);
fo(j,1,t)
fo(i,1,top-two[j]+1){
k=rmq[j-1][i];l=rmq[j-1][i+two[j-1]];
if (d[dfn[k]]<d[dfn[l]]) rmq[j][i]=k;else rmq[j][i]=l;
}
tot=n-1;
fo(i,1,n-1) add2(1,i);
fo(i,1,n) data[i][0]=data[i][1]=i;
solve(1,1,n);
fo(i,1,m) write(ans[q[i]]);
}