题目链接:4538:[Hnoi2016]网络
整体二分,用dfs序+树状数组判断当前答案是否可行
对于一段区间[l,r],我们二分得到的答案为mid,我们把[l,r]中大于mid的数据交互请求加入树状数组,同时也有撤销操作的删除
这样知道我们发现了一个询问操作,我们在树状数组中做子树查询,就可以知道当前点坏掉会影响多少条数据交互请求
设区间[l,r]中我们在当前操作的时候还存在有num个数据交互请求,我们子树查询得到的答案为ans,如果ans<num,说明存在没有受到影响的链,那么当前二分得到的答案mid就可以是这个询问的答案,换句话说当前询问的答案>=mid
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500010;
int n,m,tot=1,h[maxn],fa[maxn][20],dep[maxn];
struct edge{int to,next;}G[maxn*10];
struct ques{int u,v,w,id,b,opt,k,lca;}p[maxn];
int s[maxn],flag[maxn],tim=0,cle=0,st[maxn];
int ans[maxn],mx=0,tmp[maxn],en[maxn];
void add_edge(int x,int y){
G[++tot].to=y;G[tot].next=h[x];h[x]=tot;
}
void dfs(int x,int f){
st[x]=++tim;
dep[x]=dep[f]+1;
for (int i=1;i<=18;++i){
if (dep[x]<(1<<i)) break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for (int i=h[x];i;i=G[i].next){
int v=G[i].to;
if (v==f) continue;
fa[v][0]=x; dfs(v,x);
}en[x]=tim;
}
int query(int a,int b){
if (dep[a]<dep[b]) swap(a,b);
int t=dep[a]-dep[b];
for (int i=0;i<=18;++i)
if (t&(1<<i)) a=fa[a][i];
if (a==b) return a;
for (int i=18;~i;i--)
if (fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int lowbit(int x){return x&-x;}
void add(int x,int v){
for (int i=x;i<=n;i+=lowbit(i)){
if (flag[i]!=cle) s[i]=0,flag[i]=cle;
s[i]+=v;
}
}
int ask(int x){
int ret=0;
for (int i=x;i>=1;i-=lowbit(i))
if (flag[i]==cle) ret+=s[i];
return ret;
}
bool cmp(const ques &a,const ques &b){
return a.k<b.k||(a.k==b.k&&a.id<b.id);
}
void solve(int L,int R,int l,int r){
int mid=(L+R)>>1;
if (l>r) return;
if (L==R){
for (int i=l;i<=r;++i)
if (p[i].opt==2) ans[p[i].id]=L;
return;
}
++cle; int t=l-1,num=0;
for (int i=l;i<=r;++i){
if (p[i].opt==0){
if (p[i].w>mid){
p[i].k=1; int lca=p[i].lca; num++;
add(st[p[i].u],1); add(st[p[i].v],1);
add(st[lca],-1);
if (fa[lca][0]) add(st[fa[lca][0]],-1);
}else p[i].k=0,t++;
}else if (p[i].opt==1){
if (p[i].w>mid){
p[i].k=1; int lca=p[i].lca; num--;
add(st[p[i].u],-1); add(st[p[i].v],-1);
add(st[lca],1);
if (fa[lca][0]) add(st[fa[lca][0]],1);
}else p[i].k=0,t++;
}else{
int ret=ask(en[p[i].b])-ask(st[p[i].b]-1);
if (ret<num) p[i].k=1;
else p[i].k=0,t++;
}
}
sort(p+l,p+r+1,cmp);
solve(L,mid,l,t);
solve(mid+1,R,t+1,r);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i){
int x,y; scanf("%d%d",&x,&y);
add_edge(x,y); add_edge(y,x);
}
dfs(1,0);
for (int i=1;i<=m;++i){
int opt,x,y,z; p[i].id=i;
scanf("%d",&opt); p[i].opt=opt;
if (!opt){
scanf("%d%d%d",&x,&y,&z);
p[i].u=x; p[i].v=y; p[i].w=z;
p[i].lca=query(p[i].u,p[i].v);
mx=max(mx,z);
}else if (opt==1){
scanf("%d",&x); p[i]=p[x];
p[i].opt=1; p[i].id=i;
}else if (opt==2)scanf("%d",&p[i].b);
tmp[i]=opt;
}
solve(0,mx,1,m);
for (int i=1;i<=m;++i)
if (tmp[i]==2) printf("%d\n",ans[i]==0?-1:ans[i]);
}