传送门
题意:给定一棵树,支持添加一条路径,删除一条路径,询问不经过某一点的路径中的最大值
考虑到删除和询问最大值普通线段树很难维护
考虑把线段树上每个节点设成一个可删堆
就可以方便的维护删除和最大值了
由于询问“不经过某一点”的最大值,我们修改就对于整棵树关于这条路径的补集修改
由于路径的区间是 O ( l o g n ) O(logn) O(logn)个,那么补集也是有 O ( l o g n ) O(logn) O(logn)个,排序之后依次修改就是了
复杂度 O ( n l o g 2 n l o g l o g n ) O(nlog^2nlog_{logn}) O(nlog2nloglogn)
开始总是T飞,把重儿子那里的 > > >改成>=就过了
U p d a t e Update Update:
L e o Leo Leo说那是一组神仙数据,能把以 1 1 1为根的链式前向星做法的 l o g log log卡满……,需要随机剖分一下
#include
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=100005;
int adj[N],nxt[N<<1],to[N<<1],cnt,dfn,pos[N],dep[N],n,m;
int siz[N],fa[N],son[N],top[N];
struct heap{
priority_queue<int>A,B;
inline void push(int x){
A.push(x);
}
inline void erase(int x){
B.push(x);
}
inline int top(){
while(B.size()&&A.top()==B.top())
A.pop(),B.pop();
return A.empty()?-1:A.top();
}
}tr[N<<2];
struct ask{
int u,v,k;
}q[N<<1];
pair<int,int>p[N];
#define se second
#define fi first
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
void dfs1(int u){
siz[u]=1,son[u]=0;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa[u])continue;
fa[v]=u,dep[v]=dep[u]+1;
dfs1(v),siz[u]+=siz[v];
if(siz[v]>=siz[son[u]])son[u]=v;//就这里,别问我为什么,我也不知道
}
}
void dfs2(int u,int tp){
pos[u]=++dfn,top[u]=tp;
if(!son[u])return;
dfs2(son[u],tp);
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==son[u]||v==fa[u])continue;
dfs2(v,v);
}
}
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void update(int u,int l,int r,int st,int des,int k,int op){
if(st<=l&&r<=des){
if(op)tr[u].push(k);
else tr[u].erase(k);
return;
}
if(st<=mid)update(lc,l,mid,st,des,k,op);
if(mid<des)update(rc,mid+1,r,st,des,k,op);
}
inline int query(int u,int l,int r,int pos){
if(l==r)return tr[u].top();
if(pos<=mid)return max(tr[u].top(),query(lc,l,mid,pos));
else return max(tr[u].top(),query(rc,mid+1,r,pos));
}
inline void pathupdate(int u,int v,int k,int op){
int tot=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
p[++tot]=make_pair(pos[top[u]],pos[u]);
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
p[++tot]=make_pair(pos[u],pos[v]);
sort(p+1,p+tot+1);
p[0]=make_pair(0,0),p[tot+1]=make_pair(n+1,n+1);
for(int i=0;i<=tot;i++){
int l=p[i].se+1,r=p[i+1].fi-1;
if(l<=r)update(1,1,n,l,r,k,op);
}
}
int main(){
// freopen("lx.cpp","r",stdin);
n=read(),m=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
addedge(u,v),addedge(v,u);
}
dfs1(1),dfs2(1,1);
for(int i=1;i<=m;i++){
int op=read();
switch(op){
case 0:{
q[i].u=read(),q[i].v=read(),q[i].k=read();
pathupdate(q[i].u,q[i].v,q[i].k,1);
break;
}
case 1:{
int p=read();
pathupdate(q[p].u,q[p].v,q[p].k,0);
break;
}
case 2:{
int x=read();
cout<<query(1,1,n,pos[x])<<'\n';
break;
}
}
}
}