bzoj 1455 洛谷 P3377 左偏树+并查集

15 篇文章 0 订阅
4 篇文章 0 订阅

bzoj 1455

题意:n个人,每个人有一个分数,每个人都是一个独立的团,有两种操作:

            1、M x y,在x和y都是活的前提下,把x所在团和y所在团合并,否则忽略此操作

            2、K x 在x是活的的前提下,把x所在团分数最小的人杀死,并输出该人分数,若x已经死亡则输出0

显然,用并查集维护团的信息,每次只删除分数最小的人,并涉及合并,妥妥的左偏树模板

 

var
        n,m,x,y,tx,ty,root:longint;
        i                 :longint;
        ch                :char;
        f,sco,l,r,dis     :array[0..1000010] of longint;
        flag              :array[0..1000010] of boolean;
procedure swap(var a,b:longint);
var
        c:longint;
begin
   c:=a; a:=b; b:=c;
end;

function get_father(x:longint):longint;
begin
   if x=f[x] then exit(x);
   f[x]:=get_father(f[x]);
   exit(f[x]);
end;

function merge(a,b:longint):longint;
begin
   if (a=0) or (b=0) then exit(a+b);
   if sco[a]>sco[b] then swap(a,b);
   r[a]:=merge(r[a],b);
   if dis[l[a]]<dis[r[b]] then swap(l[a],r[a]);
   dis[a]:=dis[r[a]]+1;
   exit(a);
end;



begin
   read(n);
   for i:=1 to n do read(sco[i]);
   for i:=1 to n do f[i]:=i;
   readln(m);
   for i:=1 to m do
   begin
      read(ch);
      if ch='K' then
      begin
         readln(x);
         if flag[x] then writeln(0) else
         begin
            tx:=get_father(x);
            writeln(sco[tx]);
            flag[tx]:=true;
            f[tx]:=merge(l[tx],r[tx]);
            f[f[tx]]:=f[tx];
         end;
      end else
      begin
         readln(x,y);
         if not flag[x] and not flag[y] then
         begin
            tx:=get_father(x);
            ty:=get_father(y);
            if (tx<>ty) then
            begin
               root:=merge(tx,ty);
               f[tx]:=root;
               f[ty]:=root;
            end;
         end;
      end;
   end;
end.

洛谷 P3377 题意同上

#include<stdio.h>
#include<string.h>

int key[100010], l[100010], r[100010], dis[100010];
int father[100010], flag[100010];

void swap(int *a, int *b) {
    int c;
    c = *a;
    *a = *b;
    *b = c;
}

int get_father(int x) {
    if (x == father[x]) return(father[x]);
    father[x] = get_father(father[x]);
    return(father[x]);
}

int merge(int a, int b) {
    if ((a == 0) || (b == 0)) return(a + b);
    if (key[a] > key[b]) swap(&a, &b);
    r[a] = merge(r[a], b);
    if (dis[l[a]] < dis[r[a]]) swap(&l[a], &r[a]);
    dis[a] = dis[r[a]] + 1;
    return(a);
}

int main() {
    int n, m, t;
    int i;
    int x, y, tx, ty;

    memset(l, 0, sizeof(l));
    memset(r, 0, sizeof(r));
    memset(flag, 0, sizeof(flag));

    scanf("%d %d", &n, &m);
    for (i = 1; i <= n ; i++) {
        father[i] = i;
        scanf("%d", &key[i]);
    }
    for (i = 1; i <= m ; i++) {
        scanf("%d", &t);
        if (t == 1) {
            scanf("%d %d", &x, &y);
            if ((flag[x] == 0) && (flag[y] == 0)){ 
            tx = get_father(x);
            ty = get_father(y);
            if (tx != ty)
              father[tx] = father[ty] = merge(tx, ty);
            }
        } else {
            scanf("%d", &x);
            if (flag[x] != 0) printf("-1\n"); else {
            tx = get_father(x);
            printf("%d\n", key[tx]);
            flag[tx] = 1;
            father[father[tx]]= father[tx] = merge(l[tx], r[tx]);
            }
        }
    }
}

—— by Eirlys

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值