#include
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44525405");
}
我写的是随机堆,然后模板可见上一篇博客。
【BZOJ1455】罗马游戏 可并堆
http://blog.csdn.net/vmurder/article/details/44513511
有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:
加一条边,连接第x个节点和第y个节点
将第x个节点的权值增加v
将第x个节点所在的连通块的所有节点的权值都增加v
将所有节点的权值都增加v
输出第x个节点当前的权值
输出第x个节点所在的连通块中,权值最大的节点的权值
输出所有节点中,权值最大的节点的权值
利用可并堆的merge操作合并两堆,需要判重跳出操作。
从节点 x 向上判断一下大小更新一下堆。
然后从节点 x 向下判断一下大小更新一下堆。
向上了不起三四十行,细节,咳咳,有点多,但也不是不能写,但是向下更新确实有点醉啊。
蒟蒻写不起,但是可以给你们看一下我开始写的向上更新(没写向下所以WA了)。
void A1()
{
int x,y;
scanf("%d%d",&x,&y),val[x]+=y;
pushdown(x);
if(root[x]==x)
{
H.change(x,val[x]);
return ;
}
int last;
for(y=fa[x];y;y=fa[x])
{
if(val[x]<=val[y])return ;
int i=(x==RS),t=son[y][!i];
pushdown(y),pushdown(x);
fa[x]=fa[y],son[fa[y]][y==son[fa[y]][1]]=x;
LS=ls,RS=rs;
if(ls)fa[ls]=y;
if(rs)fa[rs]=y;
fa[y]=x,son[x][i]=y;
son[x][!i]=t;if(t)fa[t]=x;
last=y;
}
root[x]=root[last]=x;
pushdown(x);
H.remove(last);
H.insert(val[x],x);
(⊙ω⊙) 先蹲掩体后面来包辣条压压惊。
那个吧,就是把 x 的两个子节点,还有它的父亲节点都搞出来,其中注意标记的下传,然后暴力用merge函数合并一下,时间复杂度是期望 O(log2n) 的哦亲。
注意一下没有儿子啊,没有父亲啊神马的之类的细节问题就好啦。
有一个剪枝:就是判断一下如果加了权值之后不改变树构,就加完然后跳出操作。(实测这个剪枝没什么意义。
给 x 的堆顶加个标记。
加个全局标记,输出神马乱七八糟的的时候加上去就好啦。
先把到堆顶的一串点的标记传下来,然后直接输出点权就好啦。
嗯,期望时间复杂度 O(log2n) 。诶那个 n 就是 n ,因为随机数据让图很快就都连一起了。
输出 x 的堆顶元素权值。
输出所有堆顶中的最大值,这个可以额外用一个堆维护一下,就是传说中的堆套堆,但是跟什么对顶堆不是一个东西啦(Orz PoPoQQQ大爷)。
当然再写个堆多闹心,来个 multiset 搞一搞就行啦,题能过就行,时间什么的不要太在意啦。
这个堆顶怎么维护呢?
删除其中一个,具体操作是最后看哪个依然是堆顶,就删除另一个。
multiset 中是Heap.erase(Heap.find(val[???]));
先把可并堆堆顶元素从裸堆中删掉,然后都处理完了再加回去。
加入是Heap.insert(val[???]);
把堆顶元素权值删了再加,或者你写堆的话就把堆中每个点映射一下,然后修改这个点,向上向下分别比较大小维护一下堆性质就行了。
在 multiset 中的俩操作都一样了。
#include
#include
#include
#include
#include
#define N 301000
#define inf 0x3f3f3f3f
#define ls son[x][0]
#define rs son[x][1]
#define LS son[y][0]
#define RS son[y][1]
using namespace std;
multiset<int>H;
struct Mergeable_Heap
{
int son[N][2],val[N],flag[N],FLAG;
int root[N],fa[N];
int find(int x)
{
if(root[x]==x)return x;
return root[x]=find(root[x]);
}
int stk[N],top;
void init(int n)
{
val[0]=-inf;
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
H.insert(val[i]);
root[i]=i;
}
}
void pushdown(int x)
{
val[x]+=flag[x];
if(ls)flag[ls]+=flag[x];
if(rs)flag[rs]+=flag[x];
flag[x]=0;
}
int merge(int x,int y)
{
pushdown(x),pushdown(y);
if(val[x]if((x&&y)==0)return x;
int d=rand()&1;
son[x][d]=merge(son[x][d],y);
if(son[x][d])fa[son[x][d]]=x;
return x;
}
void U()
{
int x,y;
scanf("%d%d",&x,&y);
int fx=find(x),fy=find(y);
if(fx==fy)return ;
root[fx]=root[fy]=merge(fx,fy);
if(root[fx]==fx)H.erase(H.find(val[fy]));
else H.erase(H.find(val[fx]));
}
void A1()
{
int x,y,A,B;
scanf("%d%d",&x,&A);
/* if(val[x]+A>=max(val[ls],val[rs]))
{
pushdown(x);
if(fa[x]&&val[fa[x]]>=val[x]+flag[x]+A)
{
val[x]+=A;
return ;
}
}
*/
for(stk[top=1]=x,y=fa[x];y;y=fa[y])stk[++top]=y;
int head=stk[top];
H.erase(H.find(val[head]));
while(top)pushdown(stk[top--]);
val[x]+=A;
y=fa[x];
int i=(x==son[y][1]);
son[y][i]=fa[x]=0;
A=ls,B=rs;
fa[A]=fa[B]=0;
ls=rs=0;
A=merge(A,B);
if(A)fa[A]=y;
if(y)son[y][i]=A,A=head;
int last=head;
root[A]=root[x]=root[head]=merge(x,A);
root[0]=0;
pushdown(root[x]);
H.insert(val[root[x]]);
}
void A2()
{
int x,y;
scanf("%d%d",&x,&y);
H.erase(H.find(val[find(x)]));
flag[find(x)]+=y;
pushdown(root[x]);
H.insert(val[root[x]]);
}
void A3()
{
int x;
scanf("%d",&x);
FLAG+=x;
}
void F1()
{
int x,y;
scanf("%d",&x);
pushdown(x);
if(x==root[x])
{
printf("%d\n",val[x]+FLAG);
return ;
}
for(stk[top=1]=x,y=fa[x];y;y=fa[y])stk[++top]=y;
while(top)pushdown(stk[top--]);
printf("%d\n",val[x]+FLAG);
}
void F2()
{
int x;
scanf("%d",&x);
pushdown(find(x));
printf("%d\n",val[root[x]]+FLAG);
}
void F3()
{
multiset<int>::iterator it = H.end();
printf("%d\n",(*(--it))+FLAG);
}
}heap;
int n,m;
char s[5];
int main()
{
// freopen("test.in","r",stdin);
srand(252503);
int i,j,k;
scanf("%d",&n);
heap.init(n);
for(scanf("%d",&m);m--;)
{
scanf("%s",s);
if(s[0]=='U')heap.U();
else if(s[0]=='A'&&s[1]=='1')heap.A1();
else if(s[0]=='A'&&s[1]=='2')heap.A2();
else if(s[0]=='A'&&s[1]=='3')heap.A3();
else if(s[0]=='F'&&s[1]=='1')heap.F1();
else if(s[0]=='F'&&s[1]=='2')heap.F2();
else if(s[0]=='F'&&s[1]=='3')heap.F3();
}
return 0;
}
/*
2015.3.21.22:42
4
-594 -709 425 563
12
A1 3 -274
U 1 2
U 1 4
A2 1 599
A1 1 218
A1 2 777
A1 1 -300
A2 1 -877
A2 1 35
A1 4 80
U 1 3
F2 3
*/
还是蛮靠谱的,我调这么长时间一直靠的它~
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3fll
using namespace std;
long long RAND(long long L=0,long long R=INF)
{
if(L>R)swap(L,R);
return (long long)rand()*rand()*rand()*rand()%(R-L+1)+L;
}
int Rand(int L=0,int R=inf){return (int)(RAND((long long)L,(long long)R));}
int main()
{
// freopen("test.in","w",stdout);
srand((unsigned)time(NULL));
int i,j,k;
int a,b,c;
int n,m,p;
n=10,m=100;
printf("%d\n",n);
for(i=1;i<=n;i++)printf("%d ",Rand(-1000,1000));
puts("");
printf("%d\n",m);
while(m--)
{
int gailv=rand()%7;
if(gailv==0)
{
printf("U");
do{a=Rand(1,n),b=Rand(1,n);}while(a==b);
printf(" %d %d\n",a,b);
}
if(gailv==1)
{
printf("A1");
printf(" %d %d\n",Rand(1,n),Rand(-1000,1000));
}
if(gailv==2)
{
printf("A2");
printf(" %d %d\n",Rand(1,n),Rand(-1000,1000));
}
if(gailv==3)
{
printf("A3");
printf(" %d\n",Rand(-1000,1000));
}
if(gailv==4)
{
printf("F1");
printf(" %d\n",Rand(1,n));
}
if(gailv==5)
{
printf("F2");
printf(" %d\n",Rand(1,n));
}
if(gailv==6)
{
printf("F3\n");
}
}
return 0;
}