『8.24 模拟赛』ranwen的服务器

Posted fang-hao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『8.24 模拟赛』ranwen的服务器相关的知识,希望对你有一定的参考价值。

题目链接戳这里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
",ans[i]);
    }
}





以上是关于『8.24 模拟赛』ranwen的服务器的主要内容,如果未能解决你的问题,请参考以下文章

8.24-8.25联赛模拟 解题报告

8.24 周六

放置勇者:远征 v0.8.24Hotfix|欢度春节|全DLC|放置策略|容量1.8GB|中文免安装

《DSP using MATLAB》示例Example 8.24

8.24 求最短通路值

错题记录日记(8.24)