Description
有
N
N
个节点,标号从到
N
N
,这个节点一开始相互不连通。第i个节点的初始权值为
a[i]
a
[
i
]
,接下来有如下一些操作:
U
U
y
y
: 加一条边,连接第个节点和第
y
y
个节点
x
x
: 将第
x
x
个节点的权值增加
A2
A
2
x
x
: 将第
x
x
个节点所在的连通块的所有节点的权值都增加
A3
A
3
v
v
: 将所有节点的权值都增加
F1
F
1
x
x
: 输出第个节点当前的权值
F2
F
2
x
x
: 输出第个节点所在的连通块中,权值最大的节点的权值
F3
F
3
: 输出所有节点中,权值最大的节点的权值
Input
第一行包含
2
2
个正整数,
q
q
,分别表示城市的数量和旅行者数量。
第二行包含个非负整数,其中第
i
i
个整数表示
i
i
号城市的幸运值。
随后行,每行包含两个正整数
x
x
,,表示
x
x
号城市和号城市之间有一条道路相连。
随后
q
q
行,每行包含两个正整数,
y
y
表示这名旅行者的旅行计划是从号城市到
y
y
号城市
,
Q≤200000
Q
≤
200000
,
Gi≤260
G
i
≤
2
60
Output
输出需要包含
q
q
行,每行包含个非负整数,表示这名旅行者可以保留的最大幸运值。
Solution
为了巩固左偏树而写的题目,由于懒得写左偏套左偏就直接下一维用
multiset
m
u
l
t
i
s
e
t
弄了,(你不是说要巩固左偏树吗怎么能这样!!!
我还有一个小问题,就是到底左偏树的的任意节点到根的路径长是多少啊,网上有说理论复杂度
O(n)
O
(
n
)
的,然而那位大佬自己的代码也是一个一个往上跳的,并且我也没
T
T
<script type="math/tex" id="MathJax-Element-275">T</script>掉,然而还是非常懵逼,留坑???
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;
}