bzoj-1095 Hide 捉迷藏

題意:

給出一棵樹,初始所有結點都是白的;

操作有兩種:

1.修改一個結點的顏色;

2.查詢當前樹上任意兩個白點的最遠距離;

n<=100000,m<=500000;


題解:

算是把當年挖下的一個大坑填了一半吧。。。

SPOJ的QTREE4又爆棧又卡常,姿勢太醜過不去就先算了= =

樹上最遠點對的經典解法是用樹的點分治來搞;

這次多了修改,那麼就要動態的維護這個點分治;

具體來說,首先將樹分治,然後從下一層分治結構的重心向上一層重心連邊,組成一個分治樹;

這個分治樹是十分優雅的!首先它的層數不會超過log層,並且我們需要統計的信息由一個無根樹的信息轉化成了一顆子樹的信息;

可以想到,每一次修改的時候直接對某點以及其祖先進行修改就可以了,複雜度是O(logn*(操作複雜度));

對於這道題具體來說,我們要維護最遠點對,那就對於每個分治結構維護從當前重心出發,到某顆子樹的最長路(注意是到某個子樹中,即每個子樹僅算一次);

爲了維護這個“跨過重心”,我們還需要利用下一層分治結構的信息;

也就是再維護一個從某分治結構的任意點到上一層分治結構重心的最長路;

然後爲了方便求解答案,再維護出所有分治結構最長鏈的最大值就可以了;

這三個東西都是用堆來維護,堆的修改複雜度是O(logn),因此總時間複雜度爲O(nlog^2n+mlog^2n);

空間上,因爲分治結構數是O(n)的  (和線段樹的空間類似),所以第一個和第三個堆總共都只有n個元素;

第二個堆和樹套樹一樣的分析,每一層所有分治結構共有n個結點,總共不超過log層;

所以空間是O(nlogn)的;


因爲我太弱所以不會太多奇奇怪怪的堆姿勢,於是就上了可並堆;

因爲我比較懶,所以最後一個堆直接用set實現了;

因爲一開始YY錯了的原因,所以代碼非常醜非常長。。。


代碼:


#include<set>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define iter multiset<int>::iterator
using namespace std;
struct Heap
{
	int l,r,fa,val,dis;
}tr[N*20];
int next[N<<1],to[N<<1],head[N],ce,tot;
int fa[N],deep[N],size[N],root[N],ma[N],self[N],art[N],node[N][20];
char str[10];
bool ban[N];
multiset<int>st;
int merge(int x,int y)
{
	if(!x||!y)	return x+y;
	if(tr[x].val<tr[y].val)
		swap(x,y);
	tr[x].r=merge(tr[x].r,y);
	tr[tr[x].r].fa=x;
	if(tr[tr[x].l].dis<tr[tr[x].r].dis)
		swap(tr[x].l,tr[x].r);
	tr[x].dis=tr[tr[x].r].dis+1;
	return x;
}
int calc(int rt)
{
	return tr[rt].val+max(tr[tr[rt].l].val,tr[tr[rt].r].val);
}
void add(int x,int y)
{
	to[++ce]=y;
	next[ce]=head[x];
	head[x]=ce;
}
int getG(int x,int pre,int &g,int n)
{
	int size=1,temp,ma,i;
	for(i=head[x],ma=0;i;i=next[i])
	{
		if(to[i]!=pre&&!ban[to[i]])
		{
			temp=getG(to[i],x,g,n);
			ma=max(ma,temp);
			size+=temp;
		}
	}
	ma=max(ma,n-size);
	if(ma<=n/2)
		g=x;
	return size;
}
void dfs(int x,int pre,int dis,int rt)
{
	node[x][deep[rt]]=++tot;
	tr[tot].val=dis;
	root[rt]=merge(root[rt],tot);
	for(int i=head[x];i;i=next[i])
	{
		if(to[i]!=pre&&!ban[to[i]])
		{
			dfs(to[i],x,dis+1,rt);
		}
	}
}
void Build(int x,int n)
{
	ban[x]=1;
	self[x]=++tot;
	art[x]=tot;
	size[x]=1;
	if(n==1)	return ;
	int i,g,siz;
	for(i=head[x];i;i=next[i])
	{
		if(!ban[to[i]])
		{
			siz=getG(to[i],x,g,n);
			getG(to[i],x,g,siz);
			fa[g]=x;
			deep[g]=deep[x]+1;
			dfs(to[i],x,1,g);
			ma[g]=++tot;
			tr[tot].val=tr[root[g]].val;
			art[x]=merge(art[x],tot);
			size[x]++;
			Build(g,siz);
		}
	}
	if(size[x]>=2)
		st.insert(calc(art[x]));
}
void remove(int y)
{
	if(size[fa[y]]>=2)
		st.erase(st.find(calc(art[fa[y]])));
	if(root[y])
	{
		if(art[fa[y]]!=ma[y])
		{
			if(tr[tr[ma[y]].fa].l==ma[y])
				tr[tr[ma[y]].fa].l=merge(tr[ma[y]].l,tr[ma[y]].r),
				tr[tr[tr[ma[y]].fa].l].fa=tr[ma[y]].fa;
			else
				tr[tr[ma[y]].fa].r=merge(tr[ma[y]].l,tr[ma[y]].r),
				tr[tr[tr[ma[y]].fa].r].fa=tr[ma[y]].fa;
		}
		else
			art[fa[y]]=merge(tr[ma[y]].l,tr[ma[y]].r),
			tr[art[fa[y]]].fa=0;
		size[fa[y]]--;
	}
}
void resume(int y)
{
	if(root[y])
	{
		tr[ma[y]].val=tr[root[y]].val;
		tr[ma[y]].fa=tr[ma[y]].l=tr[ma[y]].r=0;
		art[fa[y]]=merge(art[fa[y]],ma[y]);
		size[fa[y]]++;
	}
	if(size[fa[y]]>=2)
		st.insert(calc(art[fa[y]]));
}
void remove2(int y)
{
	if(size[y]>=2)
		st.erase(st.find(calc(art[y])));
	if(ban[y])
	{
		if(art[y]!=self[y])
		{
			if(tr[tr[self[y]].fa].l==self[y])
				tr[tr[self[y]].fa].l=merge(tr[self[y]].l,tr[self[y]].r),
				tr[tr[tr[self[y]].fa].l].fa=tr[self[y]].fa;
			else
				tr[tr[self[y]].fa].r=merge(tr[self[y]].l,tr[self[y]].r),
				tr[tr[tr[self[y]].fa].r].fa=tr[self[y]].fa;
		}
		else
			art[y]=merge(tr[self[y]].l,tr[self[y]].r),
			tr[art[y]].fa=0;
		size[y]--;
	}
}
void resume2(int y)
{
	if(!ban[y])
	{
		tr[self[y]].val=0;
		tr[self[y]].fa=tr[self[y]].l=tr[self[y]].r=0;
		art[y]=merge(art[y],self[y]);
		size[y]++;
	}
	if(size[y]>=2)
		st.insert(calc(art[y]));
}
int main()
{
	int n,m,i,j,k,x,y,g,now;
	scanf("%d",&n);
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	tr[0].dis=-1;
	getG(1,0,g,n);
	Build(g,n);
	scanf("%d",&m);
	for(i=1,now=n;i<=m;i++)
	{
		scanf("%s",str);
		if(str[0]=='C')
		{
			scanf("%d",&x);
			if(ban[x])
			{
				remove2(x);
				resume2(x);
				for(y=x;fa[y];y=fa[y])
				{
					remove(y);
					k=node[x][deep[y]];
					if(k!=root[y])
					{
						if(tr[tr[k].fa].l==k)
							tr[tr[k].fa].l=merge(tr[k].l,tr[k].r),
							tr[tr[tr[k].fa].l].fa=tr[k].fa;
						else
							tr[tr[k].fa].r=merge(tr[k].l,tr[k].r),
							tr[tr[tr[k].fa].r].fa=tr[k].fa;
					}
					else
						root[y]=merge(tr[k].l,tr[k].r);
					resume(y);
				}
				ban[x]=0;
				now--;
			}
			else
			{
				remove2(x);
				resume2(x);
				for(y=x;fa[y];y=fa[y])
				{
					remove(y);
					k=node[x][deep[y]];
					tr[k].fa=tr[k].l=tr[k].r=tr[k].dis=0;
					root[y]=merge(root[y],k);
					resume(y);
				}
				ban[x]=1;
				now++;
			}
		}
		else
		{
			if(now==1)
				puts("0");
			else if(!now)
				puts("-1");
			else
			{
				iter it=st.end();
				it--;
				printf("%d\n",*it);
			}
		}
	}
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章