题解:
对于一个询问我们二分他的答案
k
k
,那么只用判断所有大于的路径的交集是否包含即可。
可以考虑整体二分,直接把路径一起往线段树上放,询问直接在线段树上二分就行了。
维护树上路径交可以做到
O(1)
O
(
1
)
,具体可以看这里。
也可以直接用树状数组做路径加然后查询标记数, 不过时间复杂度会多一个
logn
log
n
。
用 ST S T 表维护 LCA L C A ,总时间复杂度为 O(nlogn) O ( n log n )
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=4e5+50;
int n,m,tot,dep[N],lst[N],lg[N];
int mn[N][19],cd,sd[N];
int dfn[N],od[N],sze[N],ind;
vector <int> edge[N];
struct data {
int u,x,y,val,id;
data(int u=0,int x=0,int y=0,int val=0):u(u),x(x),y(y),val(val){}
friend inline bool operator <(const data &a,const data &b) {return a.val<b.val;}
} op[N],qry[N];
inline int getlca(int x,int y) {
x=sd[x], y=sd[y];
if(x>y) swap(x,y);
int Lg=lg[y-x+1];
return od[min(mn[x][Lg],mn[y-(1<<Lg)+1][Lg])];
}
struct chain {
int a,b,lca;
inline bool on(int x) {
if(!lca) return true;
if(lca==-1) return false;
if(dfn[lca]>dfn[x] || lst[lca]<dfn[x]) return false;
if(dfn[x]<=dfn[a] && lst[x]>=dfn[a]) return true;
if(dfn[x]<=dfn[b] && lst[x]>=dfn[b]) return true;
return false;
}
friend inline chain merge(chain a,chain b) {
if(a.lca==-1 || b.lca==-1) return (chain){0,0,-1};
if(!a.lca) return b;
if(!b.lca) return a;
if(dep[a.lca]>dep[b.lca]) swap(a,b);
if(!a.on(b.lca)) return (chain){0,0,-1};
if(a.lca==b.lca) {
int ls=getlca(a.a,b.a), ls2=getlca(a.a,b.b), rs=getlca(a.b,b.b), rs2=getlca(a.b,b.a);
if(dep[ls2]>dep[ls]) ls=ls2;
if(dep[rs2]>dep[rs]) rs=rs2;
return (chain){ls,rs,a.lca};
} else {
int ls=getlca(a.a,b.b), ls2=getlca(a.b,b.a), rs=getlca(a.a,b.a), rs2=getlca(a.b,b.b);
if(dep[ls2]>dep[ls]) ls=ls2;
if(dep[rs2]>dep[rs]) rs=rs2;
return (chain){ls,rs,b.lca};
}
}
}path[N*2];
inline void dfs(int x,int f) {
dfn[x]=++ind; sze[x]=1; dep[x]=dep[f]+1;
od[ind]=x; mn[++cd][0]=dfn[x]; sd[x]=cd;
for(int e=edge[x].size()-1;~e;e--) {
int v=edge[x][e]; if(v==f) continue;
dfs(v,x); sze[x]+=sze[v]; mn[++cd][0]=dfn[x];
} lst[x]=dfn[x]+sze[x]-1;
}
inline void inc(int k,int l,int r,int p,chain t) {
if(l==r) {path[k]=t; return;}
int mid=(l+r)>>1;
(p<=mid) ?inc(k<<1,l,mid,p,t): inc(k<<1|1,mid+1,r,p,t);
path[k]=merge(path[k<<1],path[k<<1|1]);
}
inline int ask(int k,int l,int r,int x) {
if(l>r) return -1;
if(l==r) {return !path[k].on(x)?op[l].val:-1;}
int mid=(l+r)>>1;
if(!path[k<<1|1].on(x)) return ask(k<<1|1,mid+1,r,x);
else return ask(k<<1,l,mid,x);
}
int main() {
n=rd(), m=rd();
for(int i=1;i<n;i++) {
int x=rd(), y=rd();
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs(1,0);
lg[1]=0;
for(int i=2;i<=cd;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=lg[cd];++i)
for(int j=1;j+(1<<i)-1<=cd;++j)
mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
for(int i=1;i<=m;i++) {
qry[i].u=rd();
if(!qry[i].u) {
qry[i].x=rd(), qry[i].y=rd(), qry[i].val=rd();
op[++tot]=qry[i]; op[tot].id=i;
} else qry[i].x=rd();
}
sort(op+1,op+tot+1);
for(int i=1;i<=tot;i++) qry[op[i].id].id=i;
for(int i=1;i<=m;i++) {
if(qry[i].u==0) inc(1,1,tot,qry[i].id,(chain){qry[i].x,qry[i].y,getlca(qry[i].x,qry[i].y)});
else if(qry[i].u==1) inc(1,1,tot,qry[qry[i].x].id,(chain){0,0,0});
else printf("%d\n",ask(1,1,tot,qry[i].x));
}
}