bzoj4538 [Hnoi2016]网络

本文介绍了一个网络系统故障监控的问题,需要处理服务器间的交互请求,并在服务器出现故障时更新未受影响请求的最大重要度。通过树链剖分和线段树堆等数据结构优化处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/2018/03/09/bzoj4538/
Description

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

Input

  第一行两个正整数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

Output

  对于每个type=2的事件,即服务器出现故障的事件,输出一行一个整数,描述未被影响的请求中重要度的最大
值。如果此时没有任何请求,或者所有请求均被影响,则输出-1。

Sample Input

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
Sample Output

-1
3
5
-1
1
-1
1
1
3
6
7
7
4
6
HINT

样例给出的树如下所示:

解释其中的部分询问;下面的解释中用(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。

2016.5.20新加数据一组,未重测

每次给定询问的起点终点 表示这些点 被这次使用占据了这样的一条通道 我的重要度是多少

同时还可以撤销这个询问 此外 还要询问 任何不经过当前这个点的最大重要度是多少 那么我可以针对树链剖分划分出的这Log区间去找补集覆盖上 然后在线段树每个节点上开一个可以删除的堆来维护下这个值即可 那么每次询问的时候相当于我就是去询问这个点及他处在集合的那个线段上有关系的点中最大的值是多少即可

数据似乎卡这种做法 但是不知道为什么把son[x]的判断条件从<改成<=即可ac

#include<queue>
#include<cstdio>
#include<algorithm>
#define N 110000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
struct node1{
    priority_queue<int>q1,q2;
    inline void push(int x){q1.push(x);}
    inline void del(int x){q2.push(x);}
    inline int qm(){
        while(!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
        if (q1.empty()) return -1;else return q1.top();
    }
}he[N<<1];
struct node{
    int y,next;
}data[N<<1];
struct node2{
    int a,b,v;
}qr[N<<1];
struct node3{
    int l,r;
}line[550];
struct node4{
    int left,right;
}tree[N<<1];
inline bool cmp3(const node3 &a,const node3 &b){
    return a.l<b.l;
}
int size[N],dfn[N],num,n,m,h[N],fa[N],dep[N],tp[N],son[N],root;
inline void dfs(int x){
    size[x]=1;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa[x]) continue;
        fa[y]=x;dep[y]=dep[x]+1;dfs(y);size[x]+=size[y];
        if (size[y]>=size[son[x]]) son[x]=y;
    }
}
inline void dfs1(int x,int top){
    dfn[x]=++num;tp[x]=top;
    if (son[x]) dfs1(son[x],top);
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (fa[x]==y||y==son[x]) continue;
        dfs1(y,y);
    }
}
inline void build(int &x,int l,int r){
    x=++num;if (l==r) return;int mid=l+r>>1;
    build(tree[x].left,l,mid);build(tree[x].right,mid+1,r);
}
inline void insert1(int x,int l,int r,int l1,int r1,int v){
    if (l1<=l&&r1>=r) {he[x].push(v);return;}int mid=l+r>>1;
    if (l1<=mid) insert1(tree[x].left,l,mid,l1,r1,v);
    if (r1>mid) insert1(tree[x].right,mid+1,r,l1,r1,v);
}
inline void del(int x,int l,int r,int l1,int r1,int v){
    if (l1<=l&&r1>=r) {he[x].del(v);return;}int mid=l+r>>1;
    if (l1<=mid) del(tree[x].left,l,mid,l1,r1,v);
    if (r1>mid) del(tree[x].right,mid+1,r,l1,r1,v);
}
inline int query(int x,int l,int r,int p){
    if (l==r) return he[x].qm();int mid=l+r>>1;
    int tmp=he[x].qm();
    if (p<=mid) tmp=max(tmp,query(tree[x].left,l,mid,p));
    if (p>mid) tmp=max(tmp,query(tree[x].right,mid+1,r,p));return tmp;
}
int main(){
    //freopen("bzoj4538.in","r",stdin);
    n=read();m=read();
    for (int i=1;i<n;++i){
        int x=read(),y=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;
        data[++num].y=x;data[num].next=h[y];h[y]=num;
    }dfs(1);num=0;dfs1(1,1);int tt=num;num=0;build(root,1,tt);
//  for (int i=1;i<=n;++i) printf("%d ",tp[i]);puts("");
    for (int i=1;i<=m;++i){
        int op=read(),tot=0;
        if (!op) {
            qr[i].a=read(),qr[i].b=read(),qr[i].v=read();int x=qr[i].a,y=qr[i].b,z=qr[i].v;
            while(tp[x]!=tp[y]){
                if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
                line[++tot].l=dfn[tp[x]];line[tot].r=dfn[x];x=fa[tp[x]];
            }if (dep[x]>dep[y]) swap(x,y);line[++tot].l=dfn[x];line[tot].r=dfn[y];
            sort(line+1,line+tot+1,cmp3);int last=0;
        //  for (int j=1;j<=tot;++j) printf("%d %d\n",line[j].l,line[j].r);
            for (int j=1;j<=tot;++j){
                if (last+1<=line[j].l-1) insert1(root,1,tt,last+1,line[j].l-1,z);
                last=line[j].r;
            }if (last+1<=tt) insert1(root,1,tt,last+1,tt,z); 
            continue;
        }
        if (op==1){
            int t=read();int x=qr[t].a,y=qr[t].b,z=qr[t].v;
            while(tp[x]!=tp[y]){
                if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
                line[++tot].l=dfn[tp[x]];line[tot].r=dfn[x];x=fa[tp[x]];
            }if (dep[x]>dep[y]) swap(x,y);line[++tot].l=dfn[x];line[tot].r=dfn[y];
            sort(line+1,line+tot+1,cmp3);int last=0;
            for (int j=1;j<=tot;++j){
                if (last+1<=line[j].l-1) del(root,1,tt,last+1,line[j].l-1,z);
                last=line[j].r;
            }if (last+1<=tt) del(root,1,tt,last+1,tt,z); 
            continue;
        }//puts("-----------");
        if (op==2) printf("%d\n",query(root,1,tt,dfn[read()]));
        //puts("----------");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值