HNOI2016 网络 [树链剖分]

来源:互联网 发布:淘宝图片空间协议手机 编辑:程序博客网 时间:2024/06/16 10:20

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。

思路
【树链剖分+线段树+堆】
  题意是给定一棵树,然后有若干个操作,可以新添加一条从u到v的权值为w的路径,或者将之前的一条路径删掉,动态询问不经过某个点的路径的最大权值
  首先考虑先树链剖分,然后看怎么处理这三个操作
  显然题目要求我们动态维护不经过一个点的最大路径权值,那么我们就考虑用堆
  每个线段树的结点里面存两个堆,都是大根堆,分别维护所有的入过堆的元素和已经被删除的元素,当我们需要求堆顶元素时,只需看一下两个堆的堆顶元素是否相等,相等的话顺便同时删掉,直到找到一个不相等的或者堆为空,就返回堆顶元素。这样就可以避免了如何删除路径的尴尬问题。
 接着当我们插入路径的时候,显然树链剖分沿着重链往上跳的时候可以把经过的连续路径存下来。然后我们对于这些路径取反,把取反后的路径(即跳的过程中没有经过的点集或线段集)他们的线段树的堆中加入当前需要插入路径的权值。如果是删除的话,往删除堆里加入元素就可以了。
  至于查询,就是找到之后一路往上跳,然后取一个MAX就可以了(找不到返回-1)。
代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#define maxn 100005#define lson pos<<1#define rson pos<<1|1using namespace std;  int n,m,head[maxn],cnt=1,ql,qr,qid,type,value,ans;int son[maxn],siz[maxn],fa[maxn],dep[maxn],top[maxn],id[maxn],dc;struct Save_Data{    int x,y,z;}Q[maxn<<1];struct Edge{    int to,next;}edge[maxn<<1];struct Seq{    int l,r;}qry[maxn];struct Tree{    int l,r,md;    priority_queue<int> q1,q2;    inline void push1(int x){q1.push(x);}    inline void push2(int x){q2.push(x);}    inline int top()    {        int res=-1;        while(!q2.empty()&&(q2.top()==q1.top()))    q1.pop(),q2.pop();        if(!q1.empty()) res=q1.top();        return res;    }}tree[maxn<<2];inline int read(){    int x=0; char ch=getchar();    while(ch<'0'||ch>'9')ch=getchar();    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x;  } inline bool cmp(Seq a,Seq b){    return a.l<b.l;}inline int add(int u,int v){    edge[cnt].to=v;    edge[cnt].next=head[u];    head[u]=cnt++;}void dfs1(int u,int pa,int depth){    siz[u]=1;fa[u]=pa;dep[u]=depth;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(v==pa)   continue;        dfs1(v,u,depth+1);        siz[u]+=siz[v];        if(siz[v]>siz[son[u]])  son[u]=v;    }}void dfs2(int u,int pa){    id[u]=++dc;top[u]=pa;    if(!son[u]) return;     dfs2(son[u],top[u]);    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(v!=fa[u]&&v!=son[u])        {            dfs2(v,v);        }    }}void build(int pos,int l,int r){    tree[pos].l=l;    tree[pos].r=r;    tree[pos].md=(l+r)>>1;    if(l==r)    return;    build(lson,l,tree[pos].md);    build(rson,tree[pos].md+1,r); }void update(int pos){    if(ql<=tree[pos].l&&tree[pos].r<=qr)    {        if(type==1) tree[pos].push1(value);        else        tree[pos].push2(value);        return;    }    if(ql<=tree[pos].md)    update(lson);    if(tree[pos].md<qr)     update(rson);}void query(int pos){    ans=max(ans,tree[pos].top());    if(tree[pos].l==tree[pos].r)    return;    if(qid<=tree[pos].md)   query(lson);    else query(rson); }inline void lca(int x,int y,int val){    int f1=top[x],f2=top[y];    int seq=0;    while(f1!=f2)    {        if(dep[f1]<dep[f2])        {            swap(x,y);swap(f1,f2);        }        qry[++seq].l=id[f1];        qry[seq].r=id[x];        x=fa[f1];f1=top[x];    }    if(dep[x]<dep[y])   swap(x,y);    qry[++seq].l=id[y];qry[seq].r=id[x];    int last=0;value=val;    sort(qry+1,qry+1+seq,cmp);    for(int i=1;i<=seq;++i)    {        ql=last+1;qr=qry[i].l-1;        if(ql<=qr)  update(1);        last=qry[i].r;    }    ql=last+1;qr=n;    if(ql<=qr)  update(1);}int main(){    int a,b,c,cmd;      memset(head,-1,sizeof(head));    n=read();m=read();    for(register int i=1;i<n;++i)    {        a=read();b=read();        add(a,b);add(b,a);    }    dfs1(1,0,1);    dfs2(1,1);    build(1,1,n);    for(int i=1;i<=m;++i)    {        cmd=read();        if(!cmd)        {            Q[i].x=read();Q[i].y=read();Q[i].z=read();            type=1;            lca(Q[i].x,Q[i].y,Q[i].z);        }        else if(cmd==1)        {            a=read();            type=-1;            lca(Q[a].x,Q[a].y,Q[a].z);        }        else        {            a=read();            ans=-1;            qid=id[a];            query(1);            printf("%d\n",ans);        }    }    return 0;  }  
2 0
原创粉丝点击