码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2333 SCOI2011 棘手的操作 可并堆套可并堆

时间:2015-03-03 16:42:54      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj2333   可并堆   树套树   

题目大意:给定n个节点,每个节点有一个初始权值,维护以下操作:

1.合并两个联通块

2.某个点权值+x

3.某个点所在联通块权值+x

4.所有点权值+x

5.询问某个点的权值

6.询问某个点所在联通块的最大权值

7.询问所有点之间的最大权值


2333333333333333333333333333333333333333333333333333333333333

2333333333333333333333333333333333333333333333333333333333333

2333333333333333333333333333333333333333333333333333333333333

2333333333333333333333333333333333333333333333333333333333333

2333333333333333333333333333333333333333333333333333333333333


根据题目要求 对于每个联通块,我们需要一种数据结构,可以完成以下操作:

某个点权值+x

整体权值+x

查询某个点权值

查询最大值

合并

显然用可并堆就可以搞- -


那么12356我们就解决了

4只需要维护一个全局标记即可

7需要维护所有点的最大权值,我们很容易想到所有点的最大权值就是所有联通块最大权值的最大值

于是我们需要对所有联通块维护一个数据结构,支持:

插入某个点

删除某个点

修改某个点的权值

查询最大值

这不还是堆么!于是怒写可并堆套可并堆~


细节部分欢迎自行脑补,有益于身体健康~


TMD真是恶心死我了……


2333333333333333333333333333333333333333333333333333333333333333333


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;

struct Heap{//内层随机堆
	Heap *ls,*rs,*fa;
	int val,mark;

	void Add(int x)
	{
		val+=x;
		mark+=x;
	}

	void Push_Down()
	{
		if(!mark) return ;
		if(ls) ls->Add(mark);
		if(rs) rs->Add(mark);
		mark=0;
	}

	void _Push_Down()
	{
		if(fa) fa->_Push_Down();
		Push_Down();
	}

	void Cut()
	{
		_Push_Down();
		if(!fa) return ;
		if(this==fa->ls)
			fa->ls=0x0;
		else
			fa->rs=0x0;
		fa=0x0;
	}

	Heap* Find_Root()
	{
		if(!fa) return this;
		return fa->Find_Root();
	}

	friend Heap* Merge(Heap *x,Heap *y)
	{
		if(!x) return y;
		if(!y) return x;
		if(x->val<y->val)
			swap(x,y);
		y->fa=x;
		x->Push_Down();
		if(rand()&1)
			x->ls=Merge(x->ls,y);
		else
			x->rs=Merge(x->rs,y);
		return x;
	}

}heap2[M];

struct abcd{//外层随机堆
	abcd *ls,*rs,*fa;
	Heap *root;

	void Cut()
	{
		if(!fa) return ;
		if(this==fa->ls)
			fa->ls=0x0;
		else
			fa->rs=0x0;
		fa=0x0;
	}

	friend abcd* Merge(abcd *x,abcd *y)
	{
		if(!x) return y;
		if(!y) return x;
		if(x->root->val<y->root->val)
			swap(x,y);
		y->fa=x;
		if(rand()&1)
			(x->ls=Merge(x->ls,y))->fa=x;
		else
			(x->rs=Merge(x->rs,y))->fa=x;
		return x;
	}

}*root,heap1[M];

abcd *belong[M];//记录每个内层堆堆顶在外层堆的位置

int n,m,mark,a[M];

void Union(int x,int y)//合并x和y所在堆
{
	abcd *fx=belong[heap2[x].Find_Root()-heap2];
	abcd *fy=belong[heap2[y].Find_Root()-heap2];
	if(fx==fy) return ;
	if(fx->root->val<fy->root->val) swap(fx,fy);
	fy->Cut();
	if(fy==root) (root=Merge(root->ls,root->rs))->fa=0x0;
	else (root=Merge(root,Merge(fy->ls,fy->rs)))->fa=0x0;

	fx->root=Merge(fx->root,fy->root);
	belong[fx->root-heap2]=fx;
}

void Add1(int x,int y)//单点修改
{
	abcd *fx=belong[heap2[x].Find_Root()-heap2];
	fx->Cut();heap2[x].Cut();
	
	abcd *temp1=Merge(fx->ls,fx->rs);
	if(temp1) temp1->fa=0x0;
	fx->ls=0x0;fx->rs=0x0;
	
	Heap *temp2=Merge(heap2[x].ls,heap2[x].rs);
	if(temp2) temp2->fa=0x0;
	heap2[x].ls=0x0;heap2[x].rs=0x0;
	
	

	heap2[x].val+=y;

	if(&heap2[x]!=fx->root)
		fx->root=Merge(fx->root,&heap2[x]);
	fx->root=Merge(fx->root,temp2);
	belong[fx->root-heap2]=fx;
	
	if(fx!=root)
		root=Merge(fx,root);
	root=Merge(root,temp1);
}

void Add2(int x,int y) //联通块修改
{
	abcd *fx=belong[heap2[x].Find_Root()-heap2];
	fx->Cut();
	abcd *temp=Merge(fx->ls,fx->rs);
	if(temp) temp->fa=0x0;
	fx->ls=0x0;fx->rs=0x0;

	fx->root->Add(y);

	if(root!=fx) root=Merge(root,fx);
	root=Merge(root,temp);
}

void Add3(int y)//全体修改
{
	mark+=y;
}

int Find1(int x)//单点查询
{
	heap2[x]._Push_Down();
	return heap2[x].val+mark;
}

int Find2(int x)//联通块查询
{
	return heap2[x].Find_Root()->val+mark;
}

int Find3()//整体查询
{
	return root->root->val+mark;
}

int main()
{
	
	freopen("2333.in","r",stdin);
	freopen("2333.out","w",stdout); 
	
	int i,x,y;
	char p[10];

	srand(19980402);

	cin>>n;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		heap1[i].root=&heap2[i];
		heap2[i].val=a[i];
		belong[i]=&heap1[i];
		root=Merge(root,&heap1[i]);
	}

	cin>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%s",p);
		if(p[0]=='U')
			scanf("%d%d",&x,&y),Union(x,y);
		if(p[0]=='A')
		{
			if(p[1]=='1')
				scanf("%d%d",&x,&y),Add1(x,y);
			if(p[1]=='2')
				scanf("%d%d",&x,&y),Add2(x,y);
			if(p[1]=='3')
				scanf("%d",&y),Add3(y);
		}
		if(p[0]=='F')
		{
			if(p[1]=='1')
				scanf("%d",&x),printf("%d\n",Find1(x));
			if(p[1]=='2')
				scanf("%d",&x),printf("%d\n",Find2(x));
			if(p[1]=='3')
				printf("%d\n",Find3());
		}
	}
	return 0;
}


BZOJ 2333 SCOI2011 棘手的操作 可并堆套可并堆

标签:bzoj   bzoj2333   可并堆   树套树   

原文地址:http://blog.csdn.net/popoqqq/article/details/44039327

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!