Description

  一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做
一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务
器自身)。由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,
每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的
管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的
一种:1. 在某两个服务器之间出现一条新的数据交互请求;2. 某个数据交互结束请求;3. 某个服务器出现故
障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产
生故障时依然会对需要经过该服务器的数据交互请求造成影响。你的任务是在每次出现故障时,维护未被影响的请
求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。

solution

正解:树链剖分+堆
想了个~~log8~~log3的做法,题目要我们怎么处理,我们就怎么处理
因为每一条路径只会被加入和删除一次,想到均摊复杂度的做法,我们在线段树的每一个节点上套一个堆.
对于一条路径,我们把没有在路径上的点,加入到线段树对应节点上的堆中去即可
对于加入的方法:因为树链剖分抠出的区间是一个个不相交的区间,我们抠出来排一个序,然后修改没有被覆盖到的区域即可,因为区间个数是log的,所以是对的.
区间修改时标记永久化,每一条路径只会被加入log个堆中,这样空间复杂度就成了 \(O(nlogn)\) 的了.

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=100005,M=200005;
inline int gi(){
  RG int str=0;RG char ch=getchar();
  while(ch>'9' || ch<'0')ch=getchar();
  while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
  return str;
}
int head[N],nxt[N<<1],to[N<<1],num=0,n,m,dep[N],fa[N];
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
int sz[N],son[N],top[N],id[N],DFN=0;bool d[M];
inline void dfs1(int x){
  sz[x]=1;
  for(int i=head[x];i;i=nxt[i]){
    int u=to[i];if(dep[u])continue;
    dep[u]=dep[x]+1;fa[u]=x;
    dfs1(u);
    sz[x]+=sz[u];
    if(sz[u]>=sz[son[x]])son[x]=u;
  }
}
inline void dfs2(int x,int tp){
  id[x]=++DFN;top[x]=tp;
  if(son[x])dfs2(son[x],tp);
  for(int i=head[x];i;i=nxt[i]){
    int u=to[i];
    if(u!=fa[x] && u!=son[x])dfs2(u,u);
  }
}
#define ls (o<<1)
#define rs (o<<1|1)
struct node{
  int x,id;
  node(){}
  node(int _x,int _id){x=_x;id=_id;}
  bool operator <(const node &pr)const{return x<pr.x;}
};
priority_queue<node>q[N<<2];int NOWID=0;
inline void Modify(int l,int r,int o,int sa,int se,int t){
  if(l>se || r<sa)return ;
  if(sa<=l && r<=se){
    q[o].push(node(t,NOWID));
    return ;
  }
  int mid=(l+r)>>1;
  Modify(l,mid,ls,sa,se,t);Modify(mid+1,r,rs,sa,se,t);
}
int tot=0;
struct Line{
  int l,r;
  bool operator <(const Line &pr)const{
    return l<pr.l;
  }
}st[N];
inline void updata(int x,int y,int z){
  tot=0;
  while(top[x]!=top[y]){
    if(dep[top[x]]<dep[top[y]])swap(x,y);
    st[++tot].l=id[top[x]];st[tot].r=id[x];
    x=fa[top[x]];
  }
  if(id[x]>id[y])swap(x,y);
  st[++tot].l=id[x];st[tot].r=id[y];

  sort(st+1,st+tot+1);
  int last=1;
  for(int i=1;i<=tot;i++){
    if(last<st[i].l)Modify(1,n,1,last,st[i].l-1,z);
    last=st[i].r+1;
  }
  if(last<=n)Modify(1,n,1,last,n,z);
}
inline int qry(int l,int r,int o,int sa){
  int mid=(l+r)>>1,ret=0;
  if(l!=r){
    if(sa<=mid)ret=qry(l,mid,ls,sa);
    else ret=qry(mid+1,r,rs,sa);
  }
  while(!q[o].empty()){
    node p=q[o].top();
    if(!d[p.id]){ret=Max(ret,p.x);break;}
    q[o].pop();
  }
  return ret;
}
void work()
{
  int x,y,z,op;
  n=gi();m=gi();
  for(int i=1;i<n;i++){
    x=gi();y=gi();
    link(x,y);link(y,x);
  }
  dep[1]=1;dfs1(1);dfs2(1,1);
  for(int i=1;i<=m;i++){
    op=gi();x=gi();NOWID=i;
    if(op==0){y=gi();z=gi();updata(x,y,z);}
    else if(op==1)d[x]=1;
    else{
      int tmp=qry(1,n,1,id[x]);
      if(!tmp)puts("-1");
      else printf("%d\n",tmp);
    }
  }
}

int main()
{
  work();
  return 0;
}