题目
解法
题目询问未被影响的请求中重要度的最大值,不如将其简单化,二分最大值再检验其是否受影响。
关于二分值 ( m mid),容易想到求出所有权值为 ( m mid) 的路径的交,如果交包含故障点则受影响。求路径的交有一个小 ( ext{trick}):对于两条路径 ((x,y),(z,w)),求出 ( ext{lca}(x,z), ext{lca}(x,w), ext{lca}(y,z), ext{lca}(y,w)) 并找出最深的两点 (a,b),若
- (a eq b)。路径的交为 ((a,b))。
- (a=b)。若 (a) 为某条路径的 ( m lca),路径的交为 (a);反之没有。
这样就可以在权值线段树上二分。需要维护 ((s,t,tag)),其中 (s,t) 为路径交,(tag) 为是否有路径。
需要注意的是,权值可能相同,我们需要将权值离散化使其互异。因为别忘了还有删除操作,如果将权值相同的路径直接合并在叶子节点就会导致无法分离。
求 (
m lca) 用 rmq
就可以做到 (mathcal O(nlog n))。
代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)
#define debug(...) do {cerr<<__LINE__<<" : ("#__VA_ARGS__<<") = "; Out(__VA_ARGS__); cerr<<flush;} while(0)
template <typename T> void Out(T x) {cerr<<x<<"
";}
template <typename T,typename ...I> void Out(T x,I ...NEXT) {cerr<<x<<", "; Out(NEXT...);}
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
const int maxn=1e5+5,maxm=2e5+5;
int n,m,ou[maxn<<1],id[maxn];
int dep[maxn],cnt,st[maxn<<1][21];
int lg[maxn<<1],p[maxm],num,rk[maxm];
// why is maxm?
vector <int> e[maxn];
struct Query {
int opt,a,b,c;
} q[maxm];
struct Tree {
int u,v; bool tag;
} t[maxm<<2];
void dfs(int u,int fa) {
dep[u]=dep[fa]+1,ou[++cnt]=u;
id[u]=cnt;
for(int i=0;i<e[u].size();++i) {
int v=e[u][i];
if(v==fa) continue;
dfs(v,u);
ou[++cnt]=u;
}
}
void init() {
rep(i,1,cnt) st[i][0]=ou[i];
lg[1]=0;
rep(i,2,cnt) lg[i]=lg[i>>1]+1;
rep(j,1,19) {
rep(i,1,cnt)
if(i+(1<<j)-1<=cnt) {
if(dep[st[i][j-1]]<dep[st[i+(1<<j-1)][j-1]])
st[i][j]=st[i][j-1];
else st[i][j]=st[i+(1<<j-1)][j-1];
}
}
}
int lca(int l,int r) {
l=id[l],r=id[r];
if(l>r) swap(l,r);
// important!!!
int d=lg[r-l+1];
if(dep[st[l][d]]<dep[st[r-(1<<d)+1][d]])
return st[l][d];
return st[r-(1<<d)+1][d];
}
bool cmp(int a,int b) {
return q[a].c<q[b].c;
}
bool cmpd(int a,int b) {
return dep[a]>dep[b];
}
void pushUp(int o) {
if(!o) return;
int ls=o<<1,rs=o<<1|1;
static int lc[5];
t[o].tag=1;
if((t[ls].tag|t[rs].tag)==0)
t[o].tag=0;
// 没有路径
else if(!t[rs].tag)
t[o].u=t[ls].u,
t[o].v=t[ls].v;
else if(!t[ls].tag)
t[o].u=t[rs].u,
t[o].v=t[rs].v;
else {
lc[1]=lca(t[ls].u,t[rs].u);
lc[2]=lca(t[ls].u,t[rs].v);
lc[3]=lca(t[ls].v,t[rs].u);
lc[4]=lca(t[ls].v,t[rs].v);
sort(lc+1,lc+5,cmpd);
if(lc[1]^lc[2]) t[o].u=lc[1],t[o].v=lc[2];
else if(lc[1]==lca(t[ls].u,t[ls].v) or
lc[1]==lca(t[rs].u,t[rs].v))
t[o].u=t[o].v=lc[1];
else t[o].u=t[o].v=0;
// 没有路径的交
}
}
void modify(int o,int l,int r,int pos,int x,int y) {
if(l>pos or r<pos) return;
if(l==r) return (void)(t[o].u=x,t[o].v=y,t[o].tag=1);
int mid=l+r>>1;
modify(o<<1,l,mid,pos,x,y),modify(o<<1|1,mid+1,r,pos,x,y);
pushUp(o);
}
void del(int o,int l,int r,int pos) {
if(l>pos or r<pos) return;
if(l==r) return (void)(t[o].u=t[o].v=t[o].tag=0);
int mid=l+r>>1;
del(o<<1,l,mid,pos),del(o<<1|1,mid+1,r,pos);
pushUp(o);
}
bool In(int u,int v,int x) {
if(!u and !v) return 0;
int Lca=lca(u,v);
if(lca(Lca,x)^Lca) return 0;
if(lca(u,x)!=x and lca(v,x)!=x) return 0;
return 1;
}
int query(int o,int l,int r,int er) {
if(!t[o].tag) return -1;
while(l^r) {
int mid=l+r>>1;
if(t[o<<1|1].tag and
!In(t[o<<1|1].u,t[o<<1|1].v,er)) {
l=mid+1; o=o<<1|1;
}
else {
r=mid; o<<=1;
}
}
if(!t[o].tag or In(t[o].u,t[o].v,er))
return -1;
return l;
}
int main() {
n=read(9),m=read(9);
rep(i,1,n-1) {
int u=read(9),v=read(9);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0),init();
rep(i,1,m) {
q[i].opt=read(9),q[i].a=read(9);
if(!q[i].opt) {
q[i].b=read(9),q[i].c=read(9);
p[++num]=i;
}
}
sort(p+1,p+num+1,cmp);
rep(i,1,num) rk[p[i]]=i;
rep(i,1,m) {
if(!q[i].opt) {
modify(1,1,num,rk[i],q[i].a,q[i].b);
}
else if(q[i].opt==1) {
del(1,1,num,rk[q[i].a]);
}
else {
int ans=query(1,1,num,q[i].a);
print(ans==-1?-1:q[p[ans]].c,'
');
}
}
return 0;
}