码迷,mamicode.com
首页 > 其他好文 > 详细

『8.24 模拟赛』ranwen的服务器

时间:2018-08-24 21:49:43      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:结构   cstring   主机   char   服务   inline   etc   --   code   

题目链接戳这里n(*≧▽≦*)n

题目描述

众所周知,ranwen建造出了强大的服务器网,规模十分庞大,有n个服务器,组成一个树形结构,1号点是总站,但是有时候可能会因为主机被回收,机房断电等事故造成服务器各种GG,现在有m个事件,可能为:1.查询x到根路径上第一个已经挂掉的服务器传输路径 2.x到y路径上的服务器传输路径全挂了。(不存在则输出0)



解题思路

上来先是树剖,然而只过了样例,爆0。。。

题面上提示了正解是并查集,但是并没有想出来,听完题解瞬间懂了。。。。

并查集,当然最方便的是合并操作,但是一个一个删除,显然不方便我们和并,那我们不妨倒着思考,将整棵树一开始看做是坏的,后来慢慢变好,就是慢慢加入新的边,那这样我们就很方便维护了,将并查集的fa连向当前所在的联通的的子树的根,这样我么每次查询的时候就是查询每个节点的最高的父节点向上的边的编号就好了。

但是这样会出现一个问题,一条边,可能在一开始就坏了,后来,又坏了一次,这时候我们加入边的时候就不能在第二次坏掉的时候加入这条边,那怎么办呢?

我们维护一个time数组,表示每个点向上的边最早在哪里坏掉,因为一开始坏掉,那么灾后后面不论你怎么坏,不到一开始这条边一直是坏的。这样,我们正着做一遍并查集,每次合并删除的边上的节点,然后处理出我们的time数组,讲节点深的点向上走,一直getfa到最上面。但如果跳的太远。跳过了LCA怎么办呢?不用担心这一点,因为依然我们能跳过
LCA,那么说明这个点到LCA都已经被合并了,也就是有time的值了,而现在的time值不会对这些边有影响。

所以,我们正着一遍并查集,处理坏掉的,然后暴力枚举边,得到最后好着的边合并起来,再反着做一遍并查集,如果time的值等于当前的时间,那么我们就合并坏的边,最后走到一开始全是好的的情况,将答案记录一下,倒着输出就好了。




代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000050;
int n,m,cnt=0,tot=0;
int fa[maxn],head[maxn<<1],ne[maxn<<1],to[maxn<<1],num[maxn<<1],dep[maxn],up[maxn],edge[maxn][2],tim[maxn],ans[maxn],fa_num[maxn];
struct nod{
    int fl,x,y;
};
nod q[maxn];
inline void read(int &x){
    x=0; register char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
inline void add(int f,int t,int nu){
    ne[++cnt]=head[f],head[f]=cnt,to[cnt]=t,num[cnt]=nu;
}
inline void ini(){
    for(register int i=0;i<maxn;i++)fa[i]=i;
}
inline int getfa(int x){
    if(fa[x]==x)return x;
    else return fa[x]=getfa(fa[x]);
}
inline void dfs(int now,int f){
    dep[now]=dep[f]+1;
    for(register int i=head[now];i;i=ne[i]){
        if(to[i]!=f){
            up[to[i]]=now;
            fa_num[to[i]]=num[i];
            dfs(to[i],now);
        }
    }
}
inline void operate(int x,int y,int z){
    x=getfa(x),y=getfa(y);
    while(x!=y){
        if(dep[x]<dep[y])swap(x,y);
        if(!tim[x]){
            tim[x]=z;
            fa[x]=fa[up[x]];
        }
        x=getfa(x);
    }
}
inline void add_edge(int x,int y,int z){
    while(x!=y){
        if(dep[x]<dep[y])swap(x,y);
        if(tim[x]==z){
            fa[x]=fa[up[x]];
        }
        x=up[x];
    }
}
int main(){
    ini();
    read(n),read(m);
    for(register int i=1,f,t;i<n;i++){
        read(f),read(t);
        add(f,t,i),add(t,f,i);
        edge[i][0]=f,edge[i][1]=t;
    }
    dfs(1,0);
    for(register int i=1,j;i<=m;i++){
        read(q[i].fl);
        if(q[i].fl==1)read(q[i].x);
        else {
            read(q[i].x),read(q[i].y);
            operate(q[i].x,q[i].y,i);
        }
    }
    ini();
    for(register int i=1;i<n;i++){
        int u=edge[i][0],v=edge[i][1];
        if(dep[u]<dep[v])swap(u,v);
        if(!tim[u]){
            fa[u]=v;
        }
    }
    for(register int i=m;i>=1;i--){
        if(q[i].fl==1){
            ans[++tot]=fa_num[getfa(q[i].x)];
        }
        else {
            add_edge(q[i].x,q[i].y,i);
        }
    }
    for(register int i=tot;i>=1;i--){
        printf("%d\n",ans[i]);
    }
}

『8.24 模拟赛』ranwen的服务器

标签:结构   cstring   主机   char   服务   inline   etc   --   code   

原文地址:https://www.cnblogs.com/Fang-Hao/p/9532070.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!