[HNOI2016]网络

Posted AFO过气选手

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2016]网络相关的知识,希望对你有一定的参考价值。

作为hnoi的蒟蒻,马上就要省选了,做做自己省的题目希望不要暴零

  

题目描述

一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。

由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:

  1. 在某两个服务器之间出现一条新的数据交互请求;

  2. 某个数据交互结束请求;

  3. 某个服务器出现故障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。

你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。

输入输出格式

输入格式:

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

输入输出样例

输入样例#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:
-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。

2016.5.20新加数据一组,未重测

 

 


 

题解

  标签给的是树剖+堆emmmm

   怎么搞,题目有三个操作

   1.给一段边加上一个值,(树剖模板操作)

   2.把之前某次操作的取消掉,(结合询问,不是可持久化)

   3.询问某个点,不经过这个点的其他的边的最大值。

   第三问怎么解决???

   应该大多数的人的问题都出在这里

   其实我们可以这么想,如果我们要把一条边加上一个重要值,可以考虑一下取反

   什么是取反?就是把除了那条边以外的节点都加上那个重要值,那条边丢着不管。

   有什么好处,如果询问的点在那条边上时,那条边的重要值就作废了,等同于那条边不加重要度,而当那个点在那条边以外时,那条边的重要度就起作用。

   读者可以自行画图理解一下。

   至于增加和删除的话

   搞个堆辅助一下嘛,就是把线段树的每一个节点看作一个堆就可以了。

 

 

 


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=100010;
struct trr{
    priority_queue<int>q1,q2;
    void push1(int a){q1.push(a);}
    void push2(int a){q2.push(a);}
    int Top()
    {
        while(!q2.empty()&&(q1.top()==q2.top())){q1.pop();q2.pop();}
        if(!q1.empty())return q1.top();
        else return -1;
    }
}t[N<<2];
struct node{
    int l,r;
}line[N];
struct nn{
    int next,to;
}e[N<<1];
int n,m,dep[N],head[N],xx[N],yy[N],vi[N];
int top[N],fa[N],cnt,tot,num,ans,l[N],son[N],size[N];
bool cmp(node a,node b)
{
    return a.l<b.l;
}

int read()
{
    int x=0,w=1;char ch=getchar();
    while(ch>9||ch<0){if(ch==-)w=-1;ch=getchar();}
    while(ch>=0&&ch<=9)x=x*10+ch-0,ch=getchar();
    return x*w;
}

void add(int from,int to)
{
    num++;
    e[num].to=to;
    e[num].next=head[from];
    head[from]=num;
}

void dfs1(int x)
{
    size[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int to=e[i].to;
        if(!dep[to])
        {
            dep[to]=dep[x]+1;
            fa[to]=x;
            dfs1(to);
            size[x]+=size[to];
            if(size[to]>size[son[x]])son[x]=to;
        }
    }
}

void dfs2(int x,int tp)
{
    l[x]=++tot;top[x]=tp;
    if(son[x])dfs2(son[x],tp);
    for(int i=head[x];i;i=e[i].next)
    {
        int to=e[i].to;
        if(to!=fa[x]&&to!=son[x])
        {
            dfs2(to,to);
        }
    }
}

void update(int root,int left,int right,int l,int r,int v,int f)
{
    if(left>=l&&r>=right)
    {
        if(f==0)t[root].push1(v);
        else t[root].push2(v);
        return ;
    }
    int mid=(left+right)>>1;
    if(l<=mid) update(root<<1,left,mid,l,r,v,f);
    if(r>mid)  update(root<<1|1,mid+1,right,l,r,v,f);
}

void cal1(int x,int y,int v,int f)
{
    int fx=top[x],fy=top[y];cnt=0;
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])swap(fx,fy),swap(x,y);
        line[++cnt].l=l[fx];line[cnt].r=l[x];
        x=fa[fx];fx=top[x];
    }
    if(l[x]<l[y])swap(x,y);
    line[++cnt].l=l[y];line[cnt].r=l[x];
    sort(line+1,line+cnt+1,cmp);
    int last=0;
    for(int i=1;i<=cnt;i++)
    {
        if(last+1<=line[i].l-1)
        update(1,1,n,last+1,line[i].l-1,v,f);
        last=line[i].r;
    }
    if(last+1<=n)
    update(1,1,n,last+1,n,v,f);
}

void query(int root,int left,int right,int pox)
{
    ans=max(ans,t[root].Top());
    if(left==right)return ;
    int mid=(left+right)>>1;
    if(pox<=mid)query(root<<1,left,mid,pox);
    else query(root<<1|1,mid+1,right,pox);
}

void sstart(int i)
{
    xx[i]=read(),yy[i]=read(),vi[i]=read();
    cal1(xx[i],yy[i],vi[i],0);
}

void endd()
{
    int t=read();
    cal1(xx[t],yy[t],vi[t],1);
}

int main()
{
    n=read();m=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    fa[1]=0;dep[1]=1;
    dfs1(1);
//    cout<<"qwq"<<endl;]
    dfs2(1,0);
    //cout<<"orz"<<endl;
    for(int i=1;i<=m;i++)
    {
        int type=read();
        if(type==0){sstart(i);}
        if(type==1){endd();}
        if(type==2){int x=read();ans=-1;query(1,1,n,l[x]);printf("%d\n",ans);}
    }
    return 0;
}

 

 

以上是关于[HNOI2016]网络的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4538[Hnoi2016]网络 整体二分+树状数组

[HNOI2016]网络

BZOJ 4538 [Hnoi2016]网络

[HNOI 2016]网络

bzoj4538: [Hnoi2016]网络

bzoj 4538: [Hnoi2016]网络