分析
考虑整体二分,对于操作0在树上差分,用树状数组实现,预处理 q q q个询问的 Lca \text{Lca} Lca,然后对于操作2,若满足当前修改操作都符合子树里的增加,那么放在左边,否则放在右边;对于操作0、1,若重要度小于等于 m i d mid mid,选择左区间,否则树上差分并选择右区间,但是最后修改操作要撤销,时间复杂度 O ( q l o g 2 n ) O(qlog^2n) O(qlog2n)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100101;
struct rec{int bel,rk,now,ans;}Q[N<<1],Ql[N<<1],Qr[N<<1];struct node{int y,next;}e[N<<1];
int k=1,n,m,ls[N],root,c[N],Lca[N<<1],mx,xx[N<<1],yy[N<<1],zz[N<<1],q,fat[N],dep[N],son[N],dfn[N],top[N],big[N],tot;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed max(int a,int b){return a>b?a:b;}
inline void dfs1(int x,int fa){
dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1;
for (rr int i=ls[x],mson=-1;i;i=e[i].next)
if (e[i].y!=fa){
dfs1(e[i].y,x);
son[x]+=son[e[i].y];
if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y];
}
}
inline void dfs2(int x,int linp){
dfn[x]=++tot,top[x]=linp;
if (!big[x]) return; dfs2(big[x],linp);
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].y!=fat[x]&&e[i].y!=big[x])
dfs2(e[i].y,e[i].y);
}
inline signed lca(int x,int y){
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y;
x=fat[top[x]];
}
if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
return x;
}
bool cmp(rec x,rec y){return x.rk<y.rk;}
inline signed query(int x){rr int ans=0; for (;x;x-=-x&x) ans+=c[x]; return ans;}
inline void add(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline void Update(int x,int y,int z,int zlca){
add(dfn[x],z),add(dfn[y],z),add(dfn[zlca],-z);
if (fat[zlca]) add(dfn[fat[zlca]],-z);
}
inline void update(int L,int R,int l,int r){
if (L==R){
for (rr int i=l;i<=r;++i)
if (Q[i].bel==2) Q[i].ans=L;
return;
}
rr int mid=(L+R)>>1,now=0,cntl=0,cntr=0;
for (rr int i=l;i<=r;++i)
if (Q[i].bel==2){
if (query(dfn[Q[i].now]+son[Q[i].now]-1)-query(dfn[Q[i].now]-1)==now) Ql[++cntl]=Q[i];
else Qr[++cntr]=Q[i];
}else{
if (zz[Q[i].now]<=mid) Ql[++cntl]=Q[i];
else{
rr int t=Q[i].bel?-1:1; Qr[++cntr]=Q[i];
now+=t,Update(xx[Q[i].now],yy[Q[i].now],t,Lca[Q[i].now]);
}
}
for (rr int i=1;i<=cntr;++i) if (Qr[i].bel!=2)
Update(xx[Qr[i].now],yy[Qr[i].now],Qr[i].bel?1:-1,Lca[Qr[i].now]);
for (rr int i=1;i<=cntl;++i) Q[l+i-1]=Ql[i];
for (rr int i=1;i<=cntr;++i) Q[l+cntl+i-1]=Qr[i];
if (cntl) update(L,mid,l,l+cntl-1);
if (cntr) update(mid+1,R,l+cntl,r);
}
signed main(){
n=iut(); q=iut();
for (rr int i=1;i<n;++i){
rr int x=iut(),y=iut();
e[++k]=(node){y,ls[x]},ls[x]=k,
e[++k]=(node){x,ls[y]},ls[y]=k;
}
dfs1(1,0),dfs2(1,1);
for (rr int i=1;i<=q;++i){
Q[i].bel=iut(),Q[i].rk=Q[i].now=i;
if (!Q[i].bel) xx[i]=iut(),yy[i]=iut(),mx=max(mx,zz[i]=iut()),Lca[i]=lca(xx[i],yy[i]);
else Q[i].now=iut();
}
update(-1,mx,1,q),sort(Q+1,Q+1+q,cmp);
for (rr int i=1;i<=q;++i) if (Q[i].bel==2){
if (~Q[i].ans) print(Q[i].ans);
else putchar('-'),putchar(49);
putchar(10);
}
return 0;
}