挺妙的一道题。
我们用线段树来解决这个问题。
考虑集合内加 v 这个操作。
如果我们把它转化为区间操作就好了。
那么我们要求编号连续。
怎么给每个点编号呢?首先把操作序列离线下来,然后用带权并查集维护在集合内的 相对编号 ,合并的时候把被合并的集合的 相对编号 都加上合并集合的大小即可。
时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 。
#include<bits/stdc++.h>
#define lc(x) t[x].ch[0]
#define rc(x) t[x].ch[1]
#define ll long long
using namespace std;
const int N=3e5+5;
int n,Q,fa[N],val[N],siz[N],id[N],L[N],R[N];
ll a[N],sum;
char ch[100];
struct query{
int type,x,y;
}q[N];
struct node{
ll dat,max;
}t[N<<2];
inline int read() {
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int find(int x) {
if(fa[x]==x) return x;
int y=fa[x];
fa[x]=find(fa[x]);
val[x]+=val[y];
return fa[x];
}
void unionset(int x,int y) {
int u=find(x),v=find(y);
if(u!=v) {
fa[u]=v;
val[u]+=siz[v];
siz[v]+=siz[u];
}
}
int find2(int x) {
return fa[x]==x?x:fa[x]=find2(fa[x]);
}
void unionset2(int x,int y) {
int u=find2(x),v=find2(y);
if(u!=v) {
fa[u]=v;
L[v]=min(L[v],L[u]);
R[v]=max(R[v],R[u]);
}
}
void pushup(int p) {
t[p].max=max(t[p<<1].max,t[p<<1|1].max);
}
void pushdown(int p) {
if(t[p].dat) {
t[p<<1].dat+=t[p].dat;
t[p<<1].max+=t[p].dat;
t[p<<1|1].dat+=t[p].dat;
t[p<<1|1].max+=t[p].dat;
t[p].dat=0;
}
}
void upd(int p,int l,int r,int ql,int qr,ll x) {
if(ql<=l&&r<=qr) {
t[p].max+=x;
t[p].dat+=x;
return;
}
pushdown(p);
int mid=(l+r)/2;
if(ql<=mid) upd(p<<1,l,mid,ql,qr,x);
if(mid<qr) upd(p<<1|1,mid+1,r,ql,qr,x);
pushup(p);
}
ll qry(int p,int l,int r,int ql,int qr) {
if(ql<=l&&r<=qr) {
return t[p].max;
}
pushdown(p);
int mid=(l+r)/2;
if(qr<=mid) return qry(p<<1,l,mid,ql,qr);
else if(mid<ql) return qry(p<<1|1,mid+1,r,ql,qr);
else return max(qry(p<<1,l,mid,ql,qr),qry(p<<1|1,mid+1,r,ql,qr));
}
int main() {
srand(time(0));
n=read();
for(int i=1;i<=n;i++) {
a[i]=read();
siz[i]=1;
fa[i]=i;
}
Q=read();
for(int i=1;i<=Q;i++) {
scanf("%s",ch);
if(ch[0]=='U') {
q[i].type=0;
q[i].x=read(),q[i].y=read();
unionset(q[i].x,q[i].y);
}
else if(ch[0]=='A'&&ch[1]=='1') {
q[i].type=1;
q[i].x=read(),q[i].y=read();
}
else if(ch[0]=='A'&&ch[1]=='2') {
q[i].type=2;
q[i].x=read(),q[i].y=read();
}
else if(ch[0]=='A'&&ch[1]=='3') {
q[i].type=3;
q[i].x=read();
}
else if(ch[0]=='F'&&ch[1]=='1') {
q[i].type=4;
q[i].x=read();
}
else if(ch[0]=='F'&&ch[1]=='2') {
q[i].type=5;
q[i].x=read();
}
else {
q[i].type=6;
}
}
for(int i=2;i<=n;i++) {
unionset(i,1);
}
for(int i=1;i<=n;i++) {
find(i);
id[i]=val[i]+1;
}
for(int i=1;i<=n;i++) {
fa[i]=i;
L[i]=R[i]=id[i];
}
for(int i=1;i<=n;i++) {
upd(1,1,n,id[i],id[i],a[i]);
}
for(int i=1;i<=Q;i++) {
if(q[i].type==0) {
unionset2(q[i].x,q[i].y);
}
else if(q[i].type==1) {
upd(1,1,n,id[q[i].x],id[q[i].x],q[i].y);
}
else if(q[i].type==2) {
int x=find2(q[i].x);
upd(1,1,n,L[x],R[x],q[i].y);
}
else if(q[i].type==3) {
upd(1,1,n,1,n,q[i].x);
}
else if(q[i].type==4) {
printf("%lld\n",qry(1,1,n,id[q[i].x],id[q[i].x]));
}
else if(q[i].type==5) {
int x=find2(q[i].x);
printf("%lld\n",qry(1,1,n,L[x],R[x]));
}
else {
printf("%lld\n",t[1].max);
}
}
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」