题目描述
一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。
由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:
1。 在某两个服务器之间出现一条新的数据交互请求;
2。 某个数据交互结束请求;
3。 某个服务器出现故障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。
你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。
题解
题意:
给出一个无根树。
每次给一条路径赋一个权值或取消,每次询问不过一个点的路径的最大权值。
做法:树套树
你发现增加一条路径是相对于全局的!并不是路径覆盖!
但是注意到询问的时候一定不用管经过其的交互信息。
故可以每次增加路径时对其他不在路径上的点进行覆盖。复杂度也是log的,最多加 1 。
因为查询是单点的,覆盖时的区间表示这整个内都被这个值影响。并且增加和删除在线段树里跳的地方是一致的,所以不用进行标记下传。
做线段树时时常要考虑标记的保存与下放问题。不要动不动就打lazy。要具体分析有无打标记和下方标记的需要,可以降低复杂度。标记永久化也是不错的思想(要满足可加合的性质)
树剖+线段树+堆
复杂度
O(n(logn)3)
O
(
n
(
l
o
g
n
)
3
)
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
using namespace std;
#define __ NULL
const int N=1e5+10;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
struct edge{int to,next;};
struct option{int type;int a,b,c;};
typedef pair<int,int> Pr;
#define ls (now<<1)
#define rs (now<<1|1)
struct Graph{
edge a[N<<1];int head[N];int cnt;int n;int m;option op[N<<1];
int dep[N];int I;int top[N];int id[N];int dfn[N];int fa[N];int size[N];int son[N];
priority_queue<int> tr[2][5*N];Pr st[23];int T;
inline void dfs(int u,int ff){
fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1;
for(register int v,i=head[u];i;i=a[i].next)
{
v=a[i].to;if(v==ff) continue;dfs(v,u);
if(size[v]>size[son[u]]) son[u]=v;size[u]+=size[v];
}
return;
}
inline void dfs2(int u,int F){
top[u]=F;id[u]=++I;dfn[I]=u;
if(!son[u]) return;dfs2(son[u],F);
for(register int v,i=head[u];i;i=a[i].next){v=a[i].to;if(v==fa[u]||v==son[u]) continue;dfs2(v,v);}
return;
}
void clear(){cnt=n=m=T=0;}
inline void init(){
n=read();cnt=0;m=read();register int x,y,z;
for(register int i=1;i<n;++i){
x=read();y=read();
add(x,y);add(y,x);
}
for(register int i=1;i<=m;++i){
x=y=z=0;
register int type=read();
if(type==0){
x=read();y=read();z=read();
}
else x=read();
op[i]=(option){type,x,y,z};
}
return;
}
void add(int x,int y){a[++cnt]=(edge){y,head[x]};head[x]=cnt;}
inline void update(int now,int l,int r,int L,int R,int w,int k){
if(L>R) return;
if(l>=L&&r<=R) return (void)tr[k][now].push(w);
register int mid=l+r>>1;
if(mid>=L) update(ls,l,mid,L,R,w,k);
if(mid<R) update(rs,mid+1,r,L,R,w,k);
}
inline int Get(int now){
while(!(tr[0][now].empty())&&!(tr[1][now].empty())&&tr[0][now].top()==tr[1][now].top()) tr[0][now].pop(),tr[1][now].pop();
return tr[0][now].empty()? -1:tr[0][now].top();
}
inline int Query(int now,int l,int r,int p){
if(l==r) return Get(now);
register int mid=l+r>>1;
register int x=Get(now);
if(mid>=p) return max(x,Query(ls,l,mid,p));
else return max(x,Query(rs,mid+1,r,p));
}
inline void ADD(int u,int v,int w,int k){
register int tu=top[u],tv=top[v];
st[T=1]=Pr(0,0);
while(tu!=tv){
if(dep[tu]<dep[tv]) swap(u,v),swap(tu,tv);
st[++T]=Pr(id[tu],id[u]);
u=fa[tu];tu=top[u];
}
if(dep[u]>dep[v]) swap(u,v);
st[++T]=Pr(id[u],id[v]);
st[++T]=Pr(I+1,I+1);
sort(st+1,st+1+T);
for(register int i=2;i<=T;++i) update(1,1,I,st[i-1].second+1,st[i].first-1,w,k);
return;
}
inline void solve(){
dfs(1,0);dfs2(1,1);
for(register int i=1;i<=m;++i){
if(op[i].type==0) ADD(op[i].a,op[i].b,op[i].c,0);
else if(op[i].type==1) ADD(op[op[i].a].a,op[op[i].a].b,op[op[i].a].c,1);
else if(op[i].type==2) printf("%d\n",Query(1,1,I,id[op[i].a]));
}
}
}Net;
int main(){Net.init();Net.solve();}