• cqyz oj | 猴子的战争 | 可并堆


    Description

      有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。

    Input

      第一行为整数n,表示猴子数量,编号为1..n。  接下来的n行,每行一个整数,其中第i个整数表示编号为i的猴子的力量值(不超过10^9的正整数)。  再一行为整数m,表示询问数目。  接下来的m行,每行两个整数x,y(1<=x,y<=n),x,y为猴子的编号,表示一个询问,其意义如题目描述。

    Output

      对每个询问,输出其回答。

    Sample Input 1 

    5
    20
    16
    10
    10
    4
    5
    2 3
    3 4
    3 5
    4 5
    1 5

    Sample Output 1

    7 

    Hint

    1<=n<=100000
     

    用并查集判断,
    要每次查询每个队的最大值,用堆维护,则要用可并堆,我用的斜堆。
    合并时可以弹出新开节点再插入,也可以省空间将就原节点弹出再插入。
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 100005, maxm = 100005;
    
    int w[maxm];
    int rt[maxn];
    int lc[maxm], rc[maxm], np;
    
    int read() {
        int o=0, f=1;
        char ch=getchar();
        while(!isdigit(ch)) { if(ch == '-') f=-1; ch=getchar(); }
        while(isdigit(ch)) o=o*10+ch-'0', ch=getchar();
        return o*f;
    }
    
    int merge(int A, int B) {
        if(A == 0) return B;
        if(B == 0) return A;
        if(w[A] < w[B]) swap(A, B);
        rc[A] = merge(rc[A], B);
        swap(lc[A], rc[A]);
        return A;
    }
    
    int top(int A) { return w[A]; }
    
    int pop(int A) { return merge(lc[A], rc[A]); }
    
    int push(int A, int v) {
        w[++np] = v;
        return merge(A, np);
    }
    
    int fa[maxn];
    int find(int x) { return fa[x] == x? x: fa[x] = find(fa[x]); }
    
    int reinsert(int A) {
        int nrt = pop(A);
        lc[A] = rc[A] = 0;
        w[A] /= 2;
        return merge(nrt, A);
    }
    
    int query(int x, int y) {
        int fx = find(x), fy = find(y);
        if(fx == fy) return -1;
        fa[fy] = fx;
        rt[fx] = reinsert(rt[fx]);
        rt[fy] = reinsert(rt[fy]);
        rt[fy] = rt[fx] = merge(rt[fx], rt[fy]);
        return top(rt[fx]);
    }
    
    int main() {
        int n=read();
        for(int i=1; i<=n; i++)
            w[i] = read(), rt[i] = fa[i] = i;
        int m=read();
        while(m--) {
            int i=read(), j=read();
            printf("%d
    ", query(i, j));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [刷题] 1016 部分A+B (15分)
    [刷题] 1022 D进制的A+B (20分)
    [刷题] 1021 个位数统计 (15分)
    [刷题] 1020 月饼 (25分)
    洛谷&BZOJ [POI2016]Korale
    反演魔术---二项式反演
    毒瘤养成记1: 如何卡hash
    多项式全家桶
    [CQOI]排序机械臂
    后缀自动机感性理解
  • 原文地址:https://www.cnblogs.com/de-compass/p/12050129.html
Copyright © 2020-2023  润新知