• [BZOJ]4998: 星球联盟


     题解: LCT+并查集  查询环上元素个数

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    int f[MAXN];
    int find1(int x){
        if(x==f[x])return x;
        return f[x]=find1(f[x]);
    }
    int pre[MAXN],ch[MAXN][2],res[MAXN],sz[MAXN];
    bool rt[MAXN];
    void newnode(int t){
        pre[t]=ch[t][0]=ch[t][1]=res[t]=0;rt[t]=1;
    }
    
    
    void reverse(int x){
        if(!x)return ;
        swap(ch[x][0],ch[x][1]);
        res[x]^=1;
    }
    
    void push(int x){
        if(res[x]){
    	reverse(ch[x][0]);
    	reverse(ch[x][1]);
    	res[x]^=1;
        }
    }
    
    void P(int x){
        if(!rt[x])P(find1(pre[x]));
        push(x);
    }
    
    void rotate(int x,int kind){
        int y=find1(pre[x]);
        ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y;
        if(rt[y])rt[x]=1,rt[y]=0;
        else ch[find1(pre[y])][ch[find1(pre[y])][1]==y]=x;
        pre[x]=find1(pre[y]);ch[x][kind]=y;pre[y]=x;
    }
    
    void splay(int x){
        P(x);
        while(!rt[x]){
    	if(rt[find1(pre[x])])rotate(x,ch[find1(pre[x])][0]==x);
    	else{
    	    int y=find1(pre[x]);int kind=ch[find1(pre[y])][0]==y;
    	    if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind);
    	    else rotate(y,kind),rotate(x,kind);
    	}
        }
    }
    
    void access(int x){
        int y=0;
        while(x){
    	splay(x);
    	if(ch[x][1])pre[ch[x][1]]=x,rt[ch[x][1]]=1,ch[x][1]=0;
    	if(y)rt[y]=0;
    	ch[x][1]=y;
    	y=x;x=find1(pre[x]);
        }
    }
    
    void mroot(int x){access(x);splay(x);reverse(x);}
    void Link(int x,int y){
        x=find1(x);y=find1(y);
        mroot(x);mroot(y);
        pre[x]=y;
    }
    
    bool pd(int u,int v){
        u=find1(u);v=find1(v);
        while(pre[u])u=find1(pre[u]);
        while(pre[v])v=find1(pre[v]);
        return u==v;
    }
    
    int st[MAXN],tot;
    
    void dfs(int x){
        if(!x)return ;
        st[++tot]=x;push(x);
        dfs(ch[x][0]);
        dfs(ch[x][1]);
    }
    
    void Tarjan(int u,int v){
        u=find1(u);v=find1(v);
        if(u==v)return ;
        mroot(u);access(v);splay(v);
        tot=0;dfs(v);
        inc(i,2,tot){
    	int t1=find1(st[i-1]);
    	int t2=find1(st[i]);
    	if(t1==t2)continue;
    	f[t2]=t1;sz[t1]+=sz[t2];
        }
        inc(i,1,tot)ch[st[i]][0]=ch[st[i]][1]=pre[st[i]]=0,rt[st[i]]=1;
    }
    
    int main(){
        int n=read();int m=read();int q=read();
        inc(i,1,n)newnode(i),f[i]=i,sz[i]=1;
        int u,v;
        inc(i,1,m){
    	u=read();v=read();
    	if(!pd(u,v))Link(u,v);
    	else Tarjan(u,v);
        }
        inc(i,1,q){
    	u=read();v=read();
    	if(!pd(u,v))printf("No
    "),Link(u,v);
    	else{
    	    Tarjan(u,v);
    	    int t1=find1(u);
    	    printf("%d
    ",sz[t1]);
    	}
        }
    }
    

      

    4998: 星球联盟

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 329  Solved: 195
    [Submit][Status][Discuss]

    Description

    在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。但是,组成
    联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能
    够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有
    公共隧道的路径。为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条
    新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨
    道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。

    Input

    第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
    第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
    第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。
    这些太空隧道按照输入的顺序依次建成。
    1≤N,M,P≤200000

    Output

    输出共P行。
    如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。
    如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出"No"(不含引号)。

    Sample Input

    5 3 4
    1 2
    4 3
    4 5
    2 3
    1 3
    4 5
    2 4

    Sample Output

    No
    3
    2
    5

    HINT


  • 相关阅读:
    Html中,id、name、class、type的区别
    Windows10右键添加“在此处打开命令窗口”
    yarn的安装与使用及与npm对应的命令
    TodoMVC:帮助你选择一个MV*框架
    迅速上手:使用taro构建微信小程序基础教程
    编程之性能优化知多少
    CQRS
    事件驱动之异步事件
    事件驱动下
    事件驱动上
  • 原文地址:https://www.cnblogs.com/wang9897/p/10392761.html
Copyright © 2020-2023  润新知