SPOJ QTREE Query on a tree V ——动态点分治

【题目分析】

    QTREE4的弱化版本

    建立出分治树,每个节点的堆表示到改点的最近白点距离。

    然后分治树上一直向上,取min即可。

    正确性显然,不用担心出现在同一子树的情况(不会是最优解),请自行脑补。

    然后弱渣我写了1.5h

【代码】

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define inf 0x3f3f3f3f
#define maxe 200005
#define maxn 100005
struct Heap{
	priority_queue<int, vector<int>, greater<int> > heap,del;
	void Ins(int x){heap.push(x);}
	void Del(int x){del.push(x);}
	int Size(){return heap.size()-del.size();}
	int Top(){while (del.size()&&heap.top()==del.top()) heap.pop(),del.pop();return heap.top();}
}s[maxn];

int h[maxe],to[maxe],ne[maxe],en=0,n,m,_log[maxn<<2],a[maxn<<2][20],col[maxn],tag=0,x;
int siz[maxn],mx[maxn],root,now,b[maxn<<2],top=0,pos[maxn],size,ban[maxn],T_rt,dst[maxn],fa[maxn];

void add(int a,int b){to[en]=b;ne[en]=h[a];h[a]=en++;}

void dfs(int o,int fa)
{
	siz[o]=1; mx[o]=0;
	if (!tag) b[++top]=o,pos[o]=top;
	for (int i=h[o];i>=0;i=ne[i])
		if (!ban[to[i]]&&to[i]!=fa)
		{
			dfs(to[i],o);
			if (!tag) b[++top]=o;
			siz[o]+=siz[to[i]];
			mx[o]=max(mx[o],siz[to[i]]);
		}
}

void dfs_root(int o,int fa)
{
	if (now>max(mx[o],size-siz[o])) root=o,now=max(mx[o],size-siz[o]);
	for (int i=h[o];i>=0;i=ne[i])
		if (!ban[to[i]]&&to[i]!=fa)
			dfs_root(to[i],o);
}

void dfs_dist(int o,int fa)
{
	for (int i=h[o];i>=0;i=ne[i])
		if (!ban[to[i]]&&to[i]!=fa)
			dst[to[i]]=dst[o]+1,dfs_dist(to[i],o);
}

void Divide(int o,int fat)
{
	dfs(o,-1);now=inf;size=siz[o];dfs_root(o,-1);
	int rt=root; ban[rt]=1;fa[rt]=fat;
	for (int i=h[rt];i>=0;i=ne[i])
		if (!ban[to[i]]) Divide(to[i],rt);
}

int dist(int x,int y)
{
	int ret=dst[x]+dst[y];
	x=pos[x],y=pos[y];
	if (x>y) swap(x,y);
	int l=_log[y-x+1];
	return ret-2*min(a[x][l],a[y-(1<<l)+1][l]);
}

void Delete(int o)
{
	s[o].Del(0);
	int now=fa[o];
	while (now)
	{
		s[now].Del(dist(o,now));
		now=fa[now];
	}
}

void Insert(int o)
{
	s[o].Ins(0);
	int now=fa[o];
	while (now)
	{
		s[now].Ins(dist(o,now));
		now=fa[now];
	}
}

int query(int o)
{
	int ret=inf;
	if (s[o].Size()) ret=min(ret,s[o].Top());
	int now=fa[o];
	while (now)
	{
		if (s[now].Size()) ret=min(s[now].Top()+dist(o,now),ret);
		now=fa[now];
	}
	if (ret==inf) printf("-1\n");
	else printf("%d\n",ret);
}

int main()
{
	memset(h,-1,sizeof h);
	scanf("%d",&n);
	F(i,1,n-1)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		add(a,b);add(b,a);
	}
	tag=1; dfs(1,-1); size=siz[1]; now=inf; dfs_root(1,-1); T_rt=root;
	tag=0; dfs(root,-1); dfs_dist(root,-1); tag=1;
	F(i,2,top) _log[i]=_log[i>>1]+1;
	F(i,1,top) a[i][0]=dst[b[i]];
	F(j,1,_log[top])
		for (int i=1;i+(1<<j)-1<=top;++i)
			a[i][j]=min(a[i][j-1],a[i+(1<<j-1)][j-1]);
	Divide(T_rt,0);
	scanf("%d",&m);
	F(i,1,m)
	{
		int opt; scanf("%d",&opt);
		switch(opt)
		{
			case 0:scanf("%d",&x);if (col[x]) Delete(x); else Insert(x); col[x]^=1; break;
			case 1:scanf("%d",&x);query(x); break;
		}
	}
}

  

posted @ 2017-02-19 22:00  SfailSth  阅读(182)  评论(0编辑  收藏  举报