[codevs1540]银河英雄传说

来源:互联网 发布:linux 线程默认优先级 编辑:程序博客网 时间:2024/04/28 02:51

“我们的征途是星辰大海”

银英传←

这才是题目←

思路:
加权并查集
维护f[i],t[i],cnt[i]
cnt[i]->i在当前队列中后面有多少元素
f[i]->i所在集合标志元素(队列底元素)
注意在未执行find(i)操作时,f[i]不一定为i真正的底
t[i]->i所在队列顶元素
t[i]仅在merge更新不再是队底的元素的cnt值时有意义
需要保证每个元素的f[i]的t、cnt等值时刻为实际值,这样每个元素在find后,t、cnt等可更新为实际值
有点像线段树的lazy思想?

/*4M 2 3C 1 2M 2 4C 4 2*/#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int MAXN = 200000 + 50;int f[MAXN],t[MAXN],cnt[MAXN];void init(int n){    for(int i = 1;i <= n;i ++)        f[i] = i,t[i] = i;}int n;int find(int x){    if(x == f[x])return x;    int fa = f[x];    f[x] = find(f[x]);    cnt[x] += cnt[fa];    return f[x];}void merge(int a,int b){    a = find(a);b = find(b);    find(t[b]);//t[b]不为标志元素,其值不一定为实际值    cnt[a] = cnt[t[b]] + 1;    f[a] = b;    t[b] = t[a];}char ch;int x,y;int main(){    cin >> n;    init(30000);    for(int i = 1;i <= n;i ++)    {        cin >> ch >> x >> y;        if(ch == 'M')        {            merge(x,y);        }        else         {            find(x);find(y);            if(f[x] != f[y])            {                cout << -1 << '\n';            }            else            {                if(cnt[x] < cnt[y])swap(x,y);                cout << cnt[x] - cnt[y] - 1 << '\n';            }        }    }} 

好像18年要重新动画化?emmmmm

原创粉丝点击