传送门
对没错总会有一道题分到这个编号…233333
第一眼想到线段树,处理生成树(重新编号)使在任何时间在同一个连通块里的点都在一个连续的区间,然后搞搞搞就可以了
然而要是换成可并堆的话操作还真是棘手啊…
首先我们要维护两种可并堆(一个可并堆和一个splay也可以…),以下简称a堆和b堆
a堆是按照题目中的操作合并的,也就是说有若干个小堆
b堆只有一个堆,维护的是所有a堆的堆顶(最大值),也就是说堆中的节点数等于a堆的个数
a中每一个堆顶要维护一个标记add,表示当前这个堆中键值+add为实际值
维护全局ADD,表示总体加的值
U x y :在a中找到x和y中的根fx和fy,在b中删除fx和fy;在a中合并x和y,得到新的根top;将top插入b
A1 x v :在a中找到x的根fx,在a中删除x,在b中删除fx;修改x的键值,将x插入a,得到新根top;将top插入b
A2 x v :在a中找到x的根fx,在b中删除fx;在a中修改fx的标记,在b中修改fx的键值;在b中插入fx
A3 x :ADD+=v
F1 x :在a中找到x的根fx,key(x)+add(fx)+ADD
F2 x :在a中找到x的根fx,key(fx)+add(fx)+ADD
F3 x :找到b的根fx,key(fx)+ADD
注意:
a中每个根有标记add,堆中的键值+堆顶add才是正确值;b中没有标记,维护的键值即为实际值
U中将a堆合并时由于堆顶标记不同,需要修改某一个堆中的键值,使两堆标记相同。用启发式合并,每次暴力修改较小的堆,每个点只会被合并至多 logn 次
时间复杂度 O(nlogn) *一坨常数
写完可并堆了之后发现线段树的写法之前从来没写过又去写了一发…
值得一做的题.
可并堆
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 300005
int n,m,x,y,fx,fy,top,tmp,temp,v,ADD,lastsize,lastadd;
int ls[N],rs[N],dis[N],key[N],f[N],add[N],par[N],size[N];
char opt[5];
queue <int> q;
void Add(int x,int v)//启发式
{
if (ls[x]) Add(ls[x],v);
if (rs[x]) Add(rs[x],v);
key[x]+=v;
return;
}
int find(int x)//找根
{
if (x==f[x]) return x;
f[x]=find(f[x]);
return f[x];
}
int merge(int x,int y)//合并
{
if (!x) return y;
if (!y) return x;
if (key[x]if (dis[ls[x]]if (!rs[x]) dis[x]=0;
else dis[x]=dis[rs[x]]+1;
return x;
}
int del(int x)//删除x,返回x原先所在堆中的根(若删除x之后堆为空,则返回0)
{
int p,q,re;
q=par[x];
p=merge(ls[x],rs[x]);
if (p) par[p]=q;
if (q&&ls[q]==x) ls[q]=p;
if (q&&rs[q]==x) rs[q]=p;
if (!q) re=p;
else re=find(q);
while (q)
{
if (dis[ls[q]]if (dis[rs[q]]+1==dis[q])
break;
dis[q]=dis[rs[q]]+1;
q=par[q];
}
ls[x]=rs[x]=dis[x]=par[x]=0;
return re;
}
namespace st
{
int ls[N],rs[N],dis[N],key[N],par[N];
int root;
int merge(int x,int y)//合并
{
if (!x) return y;
if (!y) return x;
if (key[x]if (dis[ls[x]]if (!rs[x]) dis[x]=0;
else dis[x]=dis[rs[x]]+1;
return x;
}
void clear()//左偏树构建
{
for (int i=1;i<=n;++i) q.push(i);
while (!q.empty())
{
x=q.front();q.pop();
if (!q.empty()) {y=q.front();q.pop();}
else break;
top=merge(x,y);
q.push(top);
}
st::root=x;
}
int del(int x)//删除x,返回根(可能为0)
{
int p,q;
q=par[x];
p=merge(ls[x],rs[x]);
if (p) par[p]=q;
if (q&&ls[q]==x) ls[q]=p;
if (q&&rs[q]==x) rs[q]=p;
if (!q) root=p;
while (q)
{
if (dis[ls[q]]if (dis[q]==dis[rs[q]]+1)
break;
dis[q]=dis[rs[q]]+1;
p=q;
q=par[q];
}
ls[x]=rs[x]=dis[x]=par[x]=0;
f[x]=x;
return root;
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d",&key[i]);
st::key[i]=key[i];
}
for (int i=1;i<=n;++i) f[i]=i,size[i]=1;
dis[0]=st::dis[0]=-1;
st::clear();
scanf("%d",&m);
for (int i=1;i<=m;++i)
{
scanf("%s",opt);
if (opt[0]=='U')
{
scanf("%d%d",&x,&y);
fx=find(x),fy=find(y);
if (fx!=fy)
{
tmp=st::del(fx);
tmp=st::del(fy);
if (size[fx]>size[fy])
swap(x,y),swap(fx,fy);
Add(fx,add[fx]-add[fy]);
top=merge(fx,fy);
if (fx) f[fx]=top;
if (fy) f[fy]=top;
size[top]=size[fx]+size[fy];
add[top]=add[fy];
temp=st::merge(tmp,top);
st::root=temp;
}
}
else if (opt[0]=='A')
{
if (opt[1]=='1')
{
scanf("%d%d",&x,&v);
fx=find(x);
tmp=st::del(fx);
lastsize=size[fx];
lastadd=add[fx];
y=del(x);
key[x]+=v;
top=merge(x,y);
if (x) f[x]=top;
if (y) f[y]=top;
size[top]=lastsize;
add[top]=lastadd;
st::key[top]=key[top]+add[top];
temp=st::merge(tmp,top);
st::root=temp;
}
else if (opt[1]=='2')
{
scanf("%d%d",&x,&v);
fx=find(x);
tmp=st::del(fx);
add[fx]+=v;
st::key[fx]=key[fx]+add[fx];
temp=st::merge(tmp,fx);
st::root=temp;
}
else if (opt[1]=='3')
{
scanf("%d",&v);
ADD+=v;
}
}
else if (opt[0]=='F')
{
if (opt[1]=='1')
{
scanf("%d",&x);
fx=find(x);
printf("%d\n",key[x]+add[fx]+ADD);
}
else if (opt[1]=='2')
{
scanf("%d",&x);
fx=find(x);
printf("%d\n",key[fx]+add[fx]+ADD);
}
else if (opt[1]=='3')
{
x=st::root;
printf("%d\n",st::key[x]+ADD);
}
}
}
return 0;
}
线段树+离线
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 300005
#define inf 2100000000
int n,m,fx,fy,cnt,ans;
char opt[N][3];
int a[N],x[N],y[N],v[N],f[N],size[N],from[N],to[N],l[N],r[N],pt[N],val[N];
int maxn[N*4],delta[N*4];
int find(int x)
{
if (x==f[x]) return x;
f[x]=find(f[x]);
return f[x];
}
void update(int now)
{
maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
}
void pushdown(int now,int l,int r,int mid)
{
if (delta[now])
{
maxn[now<<1]+=delta[now];delta[now<<1]+=delta[now];
maxn[now<<1|1]+=delta[now];delta[now<<1|1]+=delta[now];
delta[now]=0;
}
}
void build(int now,int l,int r)
{
int mid=(l+r)>>1;
if (l==r)
{
maxn[now]=val[l];
return;
}
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
void change(int now,int l,int r,int lrange,int rrange,int v)
{
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange)
{
maxn[now]+=v;
delta[now]+=v;
return;
}
pushdown(now,l,r,mid);
if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,v);
if (mid+1<=rrange) change(now<<1|1,mid+1,r,lrange,rrange,v);
update(now);
}
int query(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1,ans=-inf;
if (lrange<=l&&r<=rrange) return maxn[now];
pushdown(now,l,r,mid);
if (lrange<=mid) ans=max(ans,query(now<<1,l,mid,lrange,rrange));
if (mid+1<=rrange) ans=max(ans,query(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
for (int i=1;i<=n;++i) f[i]=i,size[i]=1;
scanf("%d",&m);
for (int i=1;i<=m;++i)
{
scanf("%s",opt[i]);
if (opt[i][0]=='U')
{
scanf("%d%d",&x[i],&y[i]);
fx=find(x[i]),fy=find(y[i]);
if (fx==fy) continue;
if (fxelse if (opt[i][0]=='A')
{
if (opt[i][1]=='1')
scanf("%d%d",&x[i],&v[i]);
else if (opt[i][1]=='2')
scanf("%d%d",&x[i],&v[i]);
else if (opt[i][1]=='3')
scanf("%d",&v[i]);
}
else if (opt[i][0]=='F')
{
if (opt[i][1]=='1')
scanf("%d",&x[i]);
else if (opt[i][1]=='2')
scanf("%d",&x[i]);
}
}
int last=0;
for (int i=1;i<=n;++i)
if (find(i)==i&&size[i]>1)
{
l[i]=last+1;
r[i]=pt[i]=last+size[i];
last+=size[i];
}
for (int i=cnt;i>=1;--i)
{
r[from[i]]=pt[from[i]]=pt[to[i]];
l[from[i]]=r[from[i]]-size[from[i]]+1;
pt[to[i]]=l[from[i]]-1;
}
for (int i=1;i<=n;++i)
if (find(i)==i&&size[i]==1)
l[i]=r[i]=++last;
for (int i=1;i<=n;++i) f[i]=i,size[i]=1,val[l[i]]=a[i];
build(1,1,n);
for (int i=1;i<=m;++i)
{
if (opt[i][0]=='U')
{
fx=find(x[i]),fy=find(y[i]);
if (fx==fy) continue;
if (fxelse if (opt[i][0]=='A')
{
if (opt[i][1]=='1')
change(1,1,n,l[x[i]],l[x[i]],v[i]);
else if (opt[i][1]=='2')
{
fx=find(x[i]);
change(1,1,n,l[fx],l[fx]+size[fx]-1,v[i]);
}
else if (opt[i][1]=='3')
change(1,1,n,1,n,v[i]);
}
else if (opt[i][0]=='F')
{
if (opt[i][1]=='1')
{
ans=query(1,1,n,l[x[i]],l[x[i]]);
printf("%d\n",ans);
}
else if (opt[i][1]=='2')
{
fx=find(x[i]);
ans=query(1,1,n,l[fx],l[fx]+size[fx]-1);
printf("%d\n",ans);
}
else if (opt[i][1]=='3')
{
ans=query(1,1,n,1,n);
printf("%d\n",ans);
}
}
}
return 0;
}