学习了可并堆,感觉不难,写起来比二叉堆都容易,但是不好理解。。。
这道题好像可并堆会被卡,但是还是练习一下吧。。
这题就是要实现一些可并堆,用一个大堆储存可并堆顶的值,左偏树或斜对就可以做啦~\(≧▽≦)/~
//DEVc++编码方式真是神奇
#include<iostream>
#include<cstdio>
#define N 300005
using namespace std;
int n,Q,x,y,ALL,root;
char p[100];
int val[N],fa[N],c[N][2],tg[N],fa1[N],c1[N][2];
int SUM(int x)
{
int ans=0;
while(fa[x])x=fa[x],ans+=tg[x];
return ans;
}
int find(int x)
{
while(fa[x])x=fa[x];
return x;
}
void down(int x)
{
if (!tg[x]) return;
val[c[x][0]]+=tg[x];
val[c[x][1]]+=tg[x];
tg[c[x][0]]+=tg[x];
tg[c[x][1]]+=tg[x];
tg[x]=0;
}
int merge(int x,int y)
{
if (!(x&&y)) return x|y;
if (val[x]<val[y]) swap(x,y);
down(x);
c[x][1]=merge(c[x][1],y);
fa[c[x][1]]=x;
swap(c[x][0],c[x][1]);
return x;
}
int del(int x)
{
down(x);
int t=merge(c[x][0],c[x][1]);
fa[t]=fa[x];
if (c[fa[x]][0]==x) c[fa[x]][0]=t;
else c[fa[x]][1]=t;
c[x][0]=c[x][1]=fa[x]=0;
return find(t);
}
int merge1(int x,int y)
{
if (!(x&&y)) return x|y;
if (val[x]<val[y]) swap(x,y);
c1[x][1]=merge1(c1[x][1],y);
fa1[c1[x][1]]=x;
swap(c1[x][0],c1[x][1]);
return x;
}
void del1(int x)
{
int t=merge1(c1[x][0],c1[x][1]);
fa1[t]=fa1[x];
if (root==x) root=t; else
if (c1[fa1[x]][0]==x) c1[fa1[x]][0]=t;
else c1[fa1[x]][1]=t;
c1[x][0]=c1[x][1]=fa1[x]=0;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&val[i]),root=merge1(root,i);
scanf("%d",&Q);
while(Q--)
{
scanf("%s",p);
if (p[0]=='U')//连边
{
scanf("%d%d",&x,&y);
int u=find(x),v=find(y);
if (u!=v)
{if (merge(u,v)==u)del1(v);else del1(u);}
}
else if (p[0]=='A')
{
if (p[1]=='1')//单点加
{
scanf("%d%d",&x,&y);
int k=find(x);del1(k);
val[x]+=y+SUM(x);
k=merge(x,del(x));
root=merge1(root,k);
}
if (p[1]=='2')//块内加
{
scanf("%d%d",&x,&y);
int k=find(x);del1(k);
tg[k]+=y;val[k]+=y;
root=merge1(root,k);
}
if (p[1]=='3')//全部加
scanf("%d",&x),ALL+=x;
}
else
{
if (p[1]=='1') scanf("%d",&x),printf("%d\n",val[x]+SUM(x)+ALL);//单点值
if (p[1]=='2') scanf("%d",&x),printf("%d\n",val[find(x)]+ALL);//块最大
if (p[1]=='3') printf("%d\n",val[root]+ALL);//总最大
}
}
}