[SCOI2011]棘手的操作

本文介绍了一个基于左偏树的数据结构问题解决方案,通过使用multiset实现节点更新与查询功能。文章详细解释了如何处理节点连接、节点权值更新及最大权值查询等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
  有NN个节点,标号从1NN,这N个节点一开始相互不连通。第i个节点的初始权值为a[i]a[i],接下来有如下一些操作:

  UU x yy: 加一条边,连接第x个节点和第yy个节点
  A1 xx v: 将第xx个节点的权值增加v
  A2A2 xx v: 将第xx个节点所在的连通块的所有节点的权值都增加v
  A3A3 vv: 将所有节点的权值都增加v
  F1F1 xx: 输出第x个节点当前的权值
  F2F2 xx: 输出第x个节点所在的连通块中,权值最大的节点的权值
  F3F3: 输出所有节点中,权值最大的节点的权值

Input
  第一行包含22个正整数nqq,分别表示城市的数量和旅行者数量。
  第二行包含n个非负整数,其中第ii个整数Gi表示ii号城市的幸运值。
  随后n1行,每行包含两个正整数 xxy,表示xx号城市和y号城市之间有一条道路相连。
  随后qq行,每行包含两个正整数xyy表示这名旅行者的旅行计划是从x号城市到yy号城市
  N20000, Q200000Q≤200000, Gi260Gi≤260

Output
  输出需要包含qq行,每行包含1个非负整数,表示这名旅行者可以保留的最大幸运值。

Solution
  为了巩固左偏树而写的题目,由于懒得写左偏套左偏就直接下一维用multisetmultiset弄了,(你不是说要巩固左偏树吗怎么能这样!!!
  我还有一个小问题,就是到底左偏树的的任意节点到根的路径长是多少啊,网上有说理论复杂度O(n)O(n)的,然而那位大佬自己的代码也是一个一个往上跳的,并且我也没TT掉,然而还是非常懵逼,留坑???

Source

//2018-4-22
//miaomiao
//
#include <bits/stdc++.h>
using namespace std;

#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define N (300000 + 5)

struct node{
    int o, lc, rc, dis, mv, sv, tag;
}tr[N];

int Mx, n, Q, rt[N], fa[N], f[N], tp, st[N];
multiset<int> all;

void Del(int now){
    multiset<int>::iterator t = all.lower_bound(now);
    all.erase(t);
}

inline void Pushdown(int a){
    if(!tr[a].tag) return;
    int lc = tr[a].lc, rc = tr[a].rc, ad = tr[a].tag;

    if(lc) tr[lc].tag += ad, tr[lc].mv += ad, tr[lc].sv += ad;
    if(rc) tr[rc].tag += ad, tr[rc].mv += ad, tr[rc].sv += ad;

    tr[a].tag = 0;
}

inline void Pushup(int a){
    tr[a].sv = tr[a].mv;
    if(tr[a].lc) tr[a].sv = max(tr[a].sv, tr[tr[a].lc].sv);
    if(tr[a].rc) tr[a].sv = max(tr[a].sv, tr[tr[a].rc].sv);
}

int Merge(int a, int b){
    if(!a || !b) return a + b;

    if(tr[a].o > tr[b].o) swap(a, b);
    fa[a] = 0;

    Pushdown(a);
    tr[a].rc = Merge(tr[a].rc, b);
    Pushup(a);

    if(tr[tr[a].lc].dis < tr[tr[a].rc].dis) swap(tr[a].lc, tr[a].rc);
    if(tr[a].lc) fa[tr[a].lc] = a; if(tr[a].rc) fa[tr[a].rc] = a;

    if(!tr[a].rc) tr[a].dis = 0;
    else tr[a].dis = tr[tr[a].rc].dis + 1;

    return a;
}

void Down(int a){
    tp = 0;
    for(int i = a; i; i = fa[i]) st[++tp] = i;
    while(tp) Pushdown(st[tp--]);
}

void Set(int a, int av){
    Down(a);

    tr[a].mv += av;
    while(fa[a]){
        Pushup(a); a = fa[a];   
    }

    Del(tr[a].sv); Pushup(a);
    all.insert(tr[a].sv);
}

void Tag(int a, int ad){
    Del(tr[a].sv);
    tr[a].tag += ad, tr[a].mv += ad, tr[a].sv += ad;
    all.insert(tr[a].sv);
}

inline int Find(int x){return x == f[x]? x: (f[x] = Find(f[x]));}
void Unit(int u, int v){
    int x = Find(u), y = Find(v);
    if(x == y) return;

    if(y < x) swap(x, y);

    if(tr[x].sv < tr[y].sv) Del(tr[x].sv);
    else Del(tr[y].sv);

    f[y] = x; Merge(rt[x], rt[y]);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("operation.in", "r", stdin);
    freopen("operation.out", "w", stdout);
#endif

    int a;

    scanf("%d", &n);
    For(i, 1, n){
        scanf("%d", &a);

        f[i] = i;
        tr[rt[i] = i] = (node){i, 0, 0, 0, a, a, 0};
        all.insert(a);
    }

    char op[5];
    int u, v, add = 0;

    scanf("%d", &Q);

    while(Q --){
        scanf("%s", op);

        if(op[0] == 'U'){
            scanf("%d%d", &u, &v); Unit(u, v);

        }else if(op[0] == 'A'){
            if(op[1] == '1'){
                scanf("%d%d", &u, &v); Set(u, v);

            }else if(op[1] == '2'){
                scanf("%d%d", &u, &v); Tag(Find(u), v);

            }else{
                scanf("%d", &v); add += v;
            }

        }else{
            if(op[1] == '1'){
                scanf("%d", &u);
                Down(u); printf("%d\n", tr[u].mv + add);

            }else if(op[1] == '2'){
                scanf("%d", &u);
                printf("%d\n", tr[Find(u)].sv + add);

            }else printf("%d\n", (*all.rbegin()) + add);
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值