zoukankan      html  css  js  c++  java
  • BZOJ_2049_[Sdoi_2008]_Cave_洞穴勘测_(LCT/并查集)

    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=2049

    给出一个森林,起始互不相连,现在有link和cut两种操作,问x,y是否在一棵树里.

    分析


    解法1:

    没有路径压缩的并查集.

    在别人博客里看来的神奇解法,其实我并不是非常了解...

    大概是在并查集的时候不雅所路径,这样就记录了哪两个点相连.

    1.link(u,v):把u翻到根上去,f[u]=v.

    2.cut(u,v):把u翻到根上去,然后f[v]=0(原来f[v]=u).

    3.query(u,v):把u翻到根上去,然后从v开始往上找,看能否找到u.

    把x翻到根上去的root(x)函数很重要,仔细想一想.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn=10000+5;
     5 int n,m,f[maxn];
     6 
     7 void root(int x){ for(int t=0,fa=f[x];x;fa=f[x]){ f[x]=t; t=x; x=fa; } }
     8 int main(){
     9     scanf("%d%d",&n,&m);
    10     char c[10];
    11     for(int i=1;i<=m;i++){
    12         scanf("%s",c);
    13         int u,v;
    14         scanf("%d%d",&u,&v);
    15         root(u);
    16         if(c[0]=='C') f[u]=v;
    17         else if(c[0]=='D') f[v]=0;
    18         else{
    19             for(;v!=u&&v;v=f[v]);
    20             puts(v==u?"Yes":"No");
    21         }
    22     }
    23     return 0;
    24 }
    View Code

    解法2:

    裸的LCT.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn=10000+5;
     5 int n,m;
     6 
     7 struct node{
     8     node* ch[2],* pa;
     9     bool rev;
    10     node(node* x):rev(false){ ch[0]=ch[1]=pa=x; }
    11     bool d(){ return pa->ch[1]==this; }
    12     bool c(){ return pa->ch[0]==this||pa->ch[1]==this; }
    13     void setc(node* x,bool d){ ch[d]=x; x->pa=this; }
    14     void push_down(){
    15         if(rev){
    16             ch[0]->rev^=true;
    17             ch[1]->rev^=true;
    18             swap(ch[0],ch[1]);
    19             rev=false;
    20         }
    21     }
    22 }* null,* t[maxn];
    23 void rot(node* x){
    24     node* pa=x->pa; bool d=x->d();
    25     pa->push_down(); x->push_down();
    26     if(pa->c()) pa->pa->setc(x,pa->d());
    27     else x->pa=pa->pa;
    28     pa->setc(x->ch[!d],d);
    29     x->setc(pa,!d);
    30 }
    31 void fix(node* x){
    32     if(x->c()) fix(x->pa);
    33     x->push_down();
    34 }
    35 void splay(node* x){
    36     fix(x);
    37     while(x->c())
    38         if(!x->pa->c()) rot(x);
    39         else x->d()==x->pa->d()?(rot(x->pa),rot(x)):(rot(x),rot(x));
    40 }
    41 void access(node* x){
    42     node* t=x;
    43     for(node* y=null;x!=null;y=x, x=x->pa){
    44         splay(x);
    45         x->ch[1]=y;
    46     }
    47     splay(t);
    48 }
    49 node* find_root(node* x){
    50     access(x);
    51     for(;x->ch[0]!=null;x=x->ch[0]);
    52     return x;
    53 }
    54 void make_root(node* x){
    55     access(x);
    56     x->rev^=true;
    57 }
    58 void link(node* x,node* y){
    59     make_root(x);
    60     x->pa=y;
    61 }
    62 void cut(node* x,node* y){
    63     make_root(x);
    64     access(y);
    65     x->pa=null; y->ch[0]=null;
    66 }
    67 int main(){
    68     null=new node(NULL);
    69     scanf("%d%d",&n,&m);
    70     for(int i=1;i<=n;i++) t[i]=new node(null);
    71     for(int i=1;i<=m;i++){
    72         int u,v; char c[10];
    73         scanf("%s%d%d",c,&u,&v);
    74         if(c[0]=='C') link(t[u],t[v]);
    75         else if(c[0]=='D') cut(t[u],t[v]);
    76         else puts(find_root(t[u])==find_root(t[v])?"Yes":"No");
    77     }
    78     return 0;
    79 }
    View Code

    2049: [Sdoi2008]Cave 洞穴勘测

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 6349  Solved: 2946
    [Submit][Status][Discuss]

    Description

    辉 辉热衷于洞穴勘测。某天,他按照地图来到了一片被标记为JSZX的洞穴群地区。经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通 道组成,并且每条通道连接了恰好两个洞穴。假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些 通道则被称之为这两个洞穴之间的一条路径。洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结 果,123号洞穴和127号洞穴之间有时会出现一条通道,有时这条通道又会因为某种稀奇古怪的原因被毁。辉辉有一台监测仪器可以实时将通道的每一次改变状 况在辉辉手边的终端机上显示:如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v 如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v 经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。因而,辉辉坚信这是由于某种本质 规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。然而,终于有一天,辉辉在堆积成山的演算纸中 崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。

    Input

    第 一行为两个正整数n和m,分别表示洞穴的个数和终端机上出现过的指令的个数。以下m行,依次表示终端机上出现的各条指令。每行开头是一个表示指令种类的字 符串s("Connect”、”Destroy”或者”Query”,区分大小写),之后有两个整数u和v (1≤u, v≤n且u≠v) 分别表示两个洞穴的编号。

    Output

    对每个Query指令,输出洞穴u和洞穴v是否互相连通:是输出”Yes”,否则输出”No”。(不含双引号)

    Sample Input

    样例输入1 cave.in
    200 5
    Query 123 127
    Connect 123 127
    Query 123 127
    Destroy 127 123
    Query 123 127
    样例输入2 cave.in

    3 5
    Connect 1 2
    Connect 3 1
    Query 2 3
    Destroy 1 3
    Query 2 3



    Sample Output

    样例输出1 cave.out
    No
    Yes
    No


    样例输出2 cave.out

    Yes
    No

    HINT

    数据说明 10%的数据满足n≤1000, m≤20000 20%的数据满足n≤2000, m≤40000 30%的数据满足n≤3000, m≤60000 40%的数据满足n≤4000, m≤80000 50%的数据满足n≤5000, m≤100000 60%的数据满足n≤6000, m≤120000 70%的数据满足n≤7000, m≤140000 80%的数据满足n≤8000, m≤160000 90%的数据满足n≤9000, m≤180000 100%的数据满足n≤10000, m≤200000 保证所有Destroy指令将摧毁的是一条存在的通道本题输入、输出规模比较大,建议cc++选手使用scanf和printf进行IO操作以免超时

    Source

  • 相关阅读:
    Azure PowerShell (2) 修改Azure订阅名称
    Windows Azure Platform Introduction (11) 了解Org ID、Windows Azure订阅、账户
    Azure PowerShell (3) 上传证书
    Azure PowerShell (1) PowerShell入门
    Windows Azure Service Bus (2) 队列(Queue)入门
    Windows Azure Service Bus (1) 基础
    Windows Azure Cloud Service (10) Role的生命周期
    Windows Azure Cloud Service (36) 在Azure Cloud Service配置SSL证书
    Android studio 使用心得(一)—android studio快速掌握快捷键
    android 签名、混淆打包
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5536402.html
Copyright © 2011-2022 走看看