• 【中山纪念中学六年级模拟赛】纸人 题解


    题目大意

    \(n\) 个纸人,有三种操作

    • C x y ,把 \(x\) 所在队列接到 \(y\) 所在队列后面
    • F x 烧掉 \(x\)\(x\) 后面的纸人
    • Q x 询问 \(x\) 所在队列的队头、队尾,若 \(x\) 被烧,输出 -1

    可能出现烧掉烧掉的纸人,或者将烧掉的纸人合并,请自动忽略

    Sample Input

    5 9
    C 1 2
    C 2 3
    Q 2
    C 4 5
    Q 4
    F 2
    Q 3
    C 4 3
    Q 3
    

    Sample Output

    3 1
    5 4
    3 3
    3 4
    

    题解

    用并查集,可以暴力烧纸人

    因为烧是连续的,不会重复,所以每个纸人只会烧 1 次,均摊 \(O(n)\)

    其他两个操作,用并查集维护最后点即可

    Code

    #include<bits/stdc++.h>
    using namespace std;
    inline int Rd() {
    	register int x=0;
    	char C=getchar();
    	for(;C<'0'||C>'9';C=getchar()) ;
    	for(;C>'/'&&C<':';C=getchar()) x=(x<<1)+(x<<3)+(C^48);
    	return x;
    }
    const int N=500005; 
    int n,T,vis[N],fa[N],ls[N],rf[N],ff[N];
    char opt;
    int fnd(int x) { return fa[x]==x?x:fa[x]=fnd(fa[x]); }
    void fre(int x) { vis[x]=1; if(rf[x]^x && !vis[rf[x]])fre(rf[x]); }
    int main() {
    	// freopen("e.in","r",stdin);
    	// freopen("e.out","w",stdout);
    	n=Rd(),T=Rd();
    	for(int i=1;i<=n;i++)
    		ff[i]=fa[i]=rf[i]=ls[i]=i;
    	for(int x,y,p,q;T--;) {
    		do opt=getchar();while(opt<'A'||opt>'Z');
    		x=Rd();
    		if(opt=='Q') {
    			if(vis[x])puts("-1");
    			else printf("%d %d\n",fnd(x),ls[fnd(x)]);
    		} else if(opt=='C') {
    			y=Rd();
    			if(vis[x] || vis[y])continue;
    			p=fnd(x),q=fnd(y);
    			if(p==q)continue;
    			rf[ls[q]]=p,ff[p]=ls[q];
    			fa[p]=q,ls[q]=ls[p];
    		} else {
    			if(!vis[x])
    			ls[fnd(ff[x])]=ff[x],fre(x);
    		}
    	}
    } 
    
  • 相关阅读:
    Windows平板优化设置
    MAC OS UI设计
    使用bat/vbs/ahk对Windows下进行自动化操作
    C#在高性能计算领域为什么性能却如此不尽人意
    自定义多重搜索
    CF797E Array Queries
    标记永久化学习笔记
    P7200 [COCI2019-2020#1] Lutrija
    P1075 [NOIP2012 普及组] 质因数分解
    基础数论重学笔记
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/14583975.html
Copyright © 2020-2023  润新知