并查集是一种树型的数据结构,用于处理一些不相交集合的合并以及查询问题
其有两个基本操作:
关于其算法流程:
但是这里存在一个很显然的问题。对于一条链来说,我们查询叶子结点的祖先的时候会把所有结点都遍历一遍,为了避免这种情况,我们可以有两种策略对其优化
问题主要出现在
这样我们需要这两个问题有两套修改方案
这些大家都懂,下面看两道题道题。
给个正整数, 有次操作,每次操作删去一个数,直到每个数都被删掉,对于每次操作,求出最大的连续段的和。
4
1 3 2 5
3 4 1 2
5 4 3 0
一开始有四个数 。
第一个操作之后被删除,剩下两个连续子段和。前一个连续子段和为4,后一个为5,输出最大所以第一个操作之后的答案为5
第二个操作之后被删除,剩,答案为4
第三个操作之后被删除。剩,答案为3
最后全被删除答案为0。
我们可以把这个删除操作,考虑成增加的操作相当于从一个空序列往上添加值,加一次,求一次线段的最大和,把操作都记下来,每次与当前值和前一个答案来更新答案。
在每次在处加入新的值的时候,判断与,的位置是否已经存在,若存在,则用并查集合并,把贡献全部累加到根节点上即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+5;
#define INF 0x3f3f3f3f
ll p[maxn];
ll find(ll x){
return p[x] == x ? x : p[x] = find(p[x]);
}
ll a[maxn],b[maxn];
bool flag[maxn];
ll sum[maxn], ans[maxn];
int main(){
int n = 0;
scanf("%d", &n);
for(int i = 1;i <= n;i++){
p[i] = i;
}
for(int i = 1;i <= n;i++){
scanf("%d", a + i);
}
for(int i = 1;i <= n;i++){
scanf("%d", b + i);
}
for(int i = n;i >= 1;i--){
ll pos = b[i];
sum[pos] = a[pos];
flag[pos] = 1;
if(flag[pos - 1]){
int rx = find(pos), ry = find(pos-1);
p[rx] = ry;
sum[ry] += sum[rx];
}
if(flag[pos + 1]){
int rx = find(pos), ry = find(pos + 1);
p[rx] = ry;
sum[ry] += sum[rx];
}
ans[i-1] = max(ans[i],sum[find(pos)]);
}
for(int i = 1;i <= n;i++){
printf("%lld\n",ans[i]);
}
return 0;
}
3 5
2 1
1 2 1
2 1
1 2 3
2 1
27
9
6
直接来分析这个猜拳的过程,挑战者去找被挑战者猜拳,留在他自己位置上的概率是(赢和平),占的位置的概率是,对于有这么一次操作,场上就会发生一次这样的变动。考虑以下几点:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
#define mod(x) x % MOD
const int maxn = 4e5+5;
ll qpow(ll a,int b){
ll res = 1;
a = mod(a);
while(b){
if(b & 1) res = mod(res * a);
a = mod(a * a);
b >>= 1;
}
return mod(res);
}
int p[maxn], n, m;
ll a[maxn],b[maxn];
int find(int x){
if(x == p[x]){
return x;
}
else{
int t = p[x];
p[x] = find(p[x]);
if(t!=p[x]){
a[x] += a[t], b[x] += b[t];
}
return p[x];
}
}
int main(){
while(~scanf("%d %d",&n,&m)){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i = 1;i <= n;i++){
p[i] = i;
}
int x = 0,y = 0;
for(int i = 1; i <= m;i++){
int kind = 0;
scanf("%d",&kind);
if(kind == 1){
scanf("%d %d",&x,&y);
a[x]++,b[y]++;
p[y] = x;
a[y] -= a[x], b[y] -= b[x];
}
else if(kind == 2){
scanf("%d",&x);
int rt = find(x), res = qpow(3,n);
ll inv1 = 1ll*qpow(3,MOD-2), inv2 = mod(2 * 1ll * inv1);
ll resa = mod(qpow(inv2,a[rt])), resb = qpow(inv1,b[rt]), ans = 0;
if(rt == x){
ans = mod(mod(mod(1ll * res * resa) * resb));
}
else{
resa = mod(qpow(inv2, (a[rt] + a[x])));
resb = mod(qpow(inv1, b[rt] + b[x]));
ans = mod(mod(mod(1ll * res * resa) * resb));
}
printf("%lld\n",ans);
}
}
}
}