题目描述
一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。
由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:
在某两个服务器之间出现一条新的数据交互请求;
某个数据交互结束请求;
- 某个服务器出现故障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。
你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。
输入输出格式
输入格式:第一行两个正整数n,m,分别描述服务器和事件个数。服务器编号是从1开始的,因此n个服务器的编号依次是1,2,3,...,n。
接下来n-1行,每行两个正整数u,v,描述一条树边。u和v是服务器的编号。
接下来m行,按发生时刻依次描述每一个事件;即第i行(i=1,2,3,...,m)描述时刻i发生的事件。每行的第一个数type描述事件类型,共3种类型:
(1)若type=0,之后有三个正整数a,b,v,表示服务器a,b之间出现一条重要度为v的数据交互请求;
(2)若type=1,之后有一个正整数t,表示时刻t(也就是第t个发生的事件)出现的数据交互请求结束;
(3)若type=2,之后有一个正整数x,表示服务器x在这一时刻出现了故障。
对于每个type为2的事件,就是一次询问,即询问”当服务器x发生故障时,未被影响的请求中重要度的最大值是多少?“注意可能有某个服务器自身与自身进行数据交互的情况。2 <= n <= 10^5, 1 <= m <= 2×10^5,其他的所有输入值不超过 10^9
输出格式:对于每个type=2的事件,即服务器出现故障的事件,输出一行一个整数,描述未被影响的请求中重要度的最大值。如果此时没有任何请求,或者所有请求均被影响,则输出-1。
输入输出样例
13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2 7 2 1 0 9 5 6 2 4 2 5 1 7 0 9 12 4 0 10 5 7 2 1 2 4 2 12 1 2 2 5 2 3
-1 3 5 -1 1 -1 1 1 3 6 7 7 4 6
说明
样例给出的树如下所示:
解释其中的部分询问;下面的解释中用(a,b;t,v)表示在t时刻出现的服务器a和b之间的重
要度为v的请求:
对于第一个询问(在时刻1),此时没有任何请求,输出-1。
对于第四个询问(在时刻6),此时有两条交互(8,13;2,3),(9,12;3,5),所有询问均经过2
号服务器,输出-1。
对于第五个询问(在时刻8),此时有三条交互(8,13;2,3),(9,12;3,5),(10,12;7,1),只有交互
(10,12;7,1)没有经过2号服务器,因此输出其重要度1。
对于最后一个询问(在时刻23),此时有三条交互(9,5;12,6),(9,12;16,4),(10,5;17,7)。当3
号服务器出现故障时,只有交互(9,5;12,6)没有经过3号服务器,因此输出6。
树链剖分+线段树套大根堆。
说白了就是把 每一次向链头跳的首尾(即 [ id[top[x]] , id[x] ])存起来,排个序,
然后用线段树把重要度丢进一个堆中。
注:求最大值时 ans 初始值为 TOP(rt),即线段树中 rt 号节点的堆顶。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#define LSON rt<<1
#define RSON rt<<1|1
#define INSERT(x,k) g[x].insert_x(k)
#define REMOVE(x,k) g[x].remove_x(k)
#define TOP(x) g[x].top()
#define LSIDE(x) g[x].l
#define RSIDE(x) g[x].r
#define MAXN 100010
using namespace std;
int n,m,c=1,d=1;
int head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],top[MAXN];
struct node1{
int next,to;
}a[MAXN<<1];
struct node2{
int u,v,w;
}b[MAXN<<1];
struct node3{
priority_queue<int> q_one,q_two;
void insert_x(int x){q_one.push(x);}
void remove_x(int x){q_two.push(x);}
int top(){
while(!q_two.empty()&&q_one.top()==q_two.top()){q_one.pop();q_two.pop();}
return (q_one.empty()?-1:q_one.top());
}
int l,r;
}g[MAXN<<2];
struct node4{
int u,v;
}h[MAXN<<1];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
bool cmp(const node4 &x,const node4 &y){
if(x.u==y.u)return x.v<y.v;
return x.u<y.u;
}
inline void add(int x,int y){
a[c].to=y;
a[c].next=head[x];
head[x]=c++;
a[c].to=x;
a[c].next=head[y];
head[y]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
id[rt]=d++;top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])
dfs2(will,will);
}
}
void buildtree(int l,int r,int rt){
int mid;
LSIDE(rt)=l;
RSIDE(rt)=r;
if(l==r)return;
mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
}
void update_one(int l,int r,int c,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
INSERT(rt,c);
return;
}
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update_one(l,r,c,LSON);
if(mid<r)update_one(l,r,c,RSON);
}
void update_two(int l,int r,int c,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
REMOVE(rt,c);
return;
}
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update_two(l,r,c,LSON);
if(mid<r)update_two(l,r,c,RSON);
}
int query(int l,int r,int rt){
int mid,ans=TOP(rt);
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return ans;
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans=max(ans,query(l,r,LSON));
if(mid<r)ans=max(ans,query(l,r,RSON));
return ans;
}
void work1(int x,int y,int k){
int f=0,l=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
f++;h[f].u=id[top[x]];h[f].v=id[x];
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
f++;h[f].u=id[x];h[f].v=id[y];
sort(h+1,h+f+1,cmp);
for(int i=1;i<=f;l=h[i++].v)if(l+1<h[i].u)update_one(l+1,h[i].u-1,k,1);
if(l<n)update_one(l+1,n,k,1);
return;
}
void work2(int x,int y,int k){
int f=0,l=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
f++;h[f].u=id[top[x]];h[f].v=id[x];
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
f++;h[f].u=id[x];h[f].v=id[y];
sort(h+1,h+f+1,cmp);
for(int i=1;i<=f;l=h[i++].v)if(l+1<h[i].u)update_two(l+1,h[i].u-1,k,1);
if(l<n)update_two(l+1,n,k,1);
return;
}
void work(){
int f,x,y,k;
for(int i=1;i<=m;i++){
f=read();x=read();
if(f==0){
b[i].u=x;b[i].v=read();b[i].w=read();
work1(b[i].u,b[i].v,b[i].w);
}
if(f==1)work2(b[x].u,b[x].v,b[x].w);
if(f==2)printf("%d\n",query(id[x],id[x],1));
}
}
void init(){
int x,y;
n=read();m=read();
for(int i=1;i<n;i++){
x=read();y=read();
add(x,y);
}
deep[1]=1;
dfs1(1);
dfs2(1,1);
buildtree(1,n,1);
}
int main(){
init();
work();
return 0;
}