zoukankan      html  css  js  c++  java
  • [题解] CF1131F Asya And Kittens

    前言

    洛谷
    Codeforces

    题意

    有一个长为 (n) 的排列,一开始每个数都是一个独立的联通块。有 (n-1) 次操作,每次要求 (x_i)(y_i) 所在的联通块相邻,然后把这两个联通块合并。求一个合法的排列使得所有操作合法。保证有解。

    思路

    先说这道题的坑点,合并时 (x_i) 必须放在左边,合并时 (y_i) 必须放在右边。

    首先将每一个块看成一个独立的连通块。对于每一个连通块,可以看做是一条链。

    于是可以使用链来维护,手写。重要的是链首和链尾。

    显然初始化时,应该把每一个链的链首与链尾初始化成自己。

    而对于查找每一个点属于哪一个连通块可以使用并查集进行维护。

    并查集合并时,将左边的链连接至右边的链的头部,让后将左边的链尾设置尾右边的链尾。

    由于右连通块的父亲将置为左连通块,所以右连通块的信息已经没有用处了,就不需要更新。

    最后从整条链的链首开始,一直输出到链尾。

    Code

    时间复杂度尾 (O(α(n)n))

    #include <cstdio>
    namespace Quick_Function {
    	template <typename Temp> void Read(Temp &x) {
    		x = 0; char ch = getchar(); bool op = 0;
    		while(ch < '0' || ch > '9') { if(ch == '-') op = 1; ch = getchar(); }
    		while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }
    		if(op) x = -x;
    	}
    	template <typename T, typename... Args> void Read(T &t, Args &... args) { Read(t); Read(args...); }
    	template <typename Temp> Temp Max(Temp x, Temp y) { return x > y ? x : y; }
    	template <typename Temp> Temp Min(Temp x, Temp y) { return x < y ? x : y; }
    	template <typename Temp> Temp Abs(Temp x) { return x < 0 ? (-x) : x; }
    	template <typename Temp> void Swap(Temp &x, Temp &y) { x ^= y ^= x ^= y; }
    }
    using namespace Quick_Function;
    const int MAXN = 15e4 + 5;
    int fa[MAXN], head[MAXN], tail[MAXN];
    int nxt[MAXN], a[MAXN], n;
    struct DSU {	
    	int Find(int x) { return fa[x] == x ? x : (fa[x] = Find(fa[x])); }
    	void Union(int x, int y) {
    		int fax = Find(x), fay = Find(y);
    		if(fax == fay) return;
    		fa[fay] = fax;
    		nxt[tail[fax]] = head[fay];
    		tail[fax] = tail[fay];
    	}
    	void Init() { for(int i = 1; i <= n; i++) fa[i] = head[i] = tail[i] = i, nxt[i] = 0; }
    	void Print(int x) {
    		if(!x) return;
    		printf("%d ", x);
    		Print(nxt[x]);
    	}
    };
    DSU dsu;
    int main() {
    	Read(n); dsu.Init();
    	for(int i = 1, x, y; i < n; i++) Read(x, y), dsu.Union(x, y);
    	dsu.Print(head[dsu.Find(1)]);
    	return 0;
    }
    
  • 相关阅读:
    构造与析构的次序
    为什么析构函数常声明为虚函数
    偏移数组的二分查找
    字符串循环右移N位
    const 补充
    对类 sizeof
    指针与引用
    python小练习
    初学数据挖掘——相似性度量(一)
    每天进步一点点(二)
  • 原文地址:https://www.cnblogs.com/C202202chenkelin/p/14987738.html
Copyright © 2011-2022 走看看