1095: [ZJOI2007]Hide 捉迷藏

发现动态树分治还是挺好玩的。。。。。。。然而效率有点拙计

跑了14S多,差点以为要TLE,回头一看发现时限40S。

模板抄的PoPoQQQ大爷的,顺便看了下漆神的论文,各种吓Cry。

准备水下QTREE4,听说SPOJ的机子很慢,好虚啊。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=100000+5;
struct Heap{
	priority_queue<int>heap,del;
	void Push(int x){
		heap.push(x);
	}
	void Erase(int x){
		del.push(x);
	}
	void Pop(){
		while(del.size()&&del.top()==heap.top())
		del.pop(),heap.pop();
		heap.pop();
	}
	int Top(){
		while(del.size()&&del.top()==heap.top())
		del.pop(),heap.pop();
		return heap.top();
	}
	int Second_Top(){
		int tmp=Top();Pop();
		int ret=Top();Push(tmp);
		return ret;
	}
	int Size(){
		return heap.size()-del.size();
	}
}h1[N],h2[N],ans;
struct Edge{int to,next;bool ban;}e[N<<1];
int head[N],cnt=1;
void ins(int u,int v){
	e[++cnt]=(Edge){v,head[u],false};head[u]=cnt;
}
int log2[N<<1],st[N<<1][20],sz,dep[N],pos[N];
bool mark[N];
int fa[N];
int getsize(int u,int fa){
	int ret=1;
	for(int i=head[u];i;i=e[i].next){
		if(e[i].to==fa||e[i].ban)continue;
		ret+=getsize(e[i].to,u);
	}
	return ret;
}
int findroot(int u,int fa,int size,int& root){
	int ret=1;bool flag=true;
	for(int i=head[u];i;i=e[i].next){
		if(e[i].ban||e[i].to==fa)continue;
		int tmp=findroot(e[i].to,u,size,root);
		if(tmp<<1>size)flag=false;
		ret+=tmp;
	}
	if(size-ret<<1>size)flag=false;
	if(flag)root=u;
	return ret;
}
void dfs(int u,int fa,int depth,Heap &s){
	s.Push(depth);
	for(int i=head[u];i;i=e[i].next)
	if(!e[i].ban&&e[i].to!=fa)dfs(e[i].to,u,depth+1,s);
}
void Insert(Heap &s){
	if(s.Size()>=2)ans.Push(s.Top()+s.Second_Top());
}
void Erase(Heap &s){
	if(s.Size()>=2)ans.Erase(s.Top()+s.Second_Top());
}
int divide(int u){
	int size=getsize(u,0),root;
	findroot(u,0,size,root);
	h2[root].Push(0);
	for(int i=head[root];i;i=e[i].next)
	if(!e[i].ban){
		e[i].ban=e[i^1].ban=true;
		Heap s;
		dfs(e[i].to,0,1,s);
		int tmp=divide(e[i].to);
		fa[tmp]=root;h1[tmp]=s;
		h2[root].Push(h1[tmp].Top());
	}
	Insert(h2[root]);
	return root;
}
void dfs(int u,int fa){
	st[pos[u]=++sz][0]=dep[u]=dep[fa]+1;
	for(int i=head[u];i;i=e[i].next)
	if(e[i].to!=fa){
		dfs(e[i].to,u);
		st[++sz][0]=dep[u];
	}
}
void rmq_init(){
	for(int j=1;1<<j <=sz;j++)
	for(int i=1;i+(1<<j)-1<=sz;i++)
	st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int rmq(int x,int y){
	x=pos[x];y=pos[y];
	if(x>y)swap(x,y);
	int k=log2[y-x+1];
	return min(st[x][k],st[y-(1<<k)+1][k]);
}
int dis(int x,int y){
	return dep[x]+dep[y]-2*rmq(x,y);
}
void change(int x,bool flag){
	Erase(h2[x]);
	if(flag)h2[x].Erase(0);
	else h2[x].Push(0);
	Insert(h2[x]);
	for(int i=x;fa[i];i=fa[i]){
		Erase(h2[fa[i]]);
		if(h1[i].Size())h2[fa[i]].Erase(h1[i].Top());
		if(flag)h1[i].Erase(dis(fa[i],x));
		else h1[i].Push(dis(fa[i],x));
		if(h1[i].Size())h2[fa[i]].Push(h1[i].Top());
		Insert(h2[fa[i]]);
	}
}
int tot;
int main(){
	int n;scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		ins(u,v);ins(v,u);
	}
	divide(1);
	dfs(1,0);
	for(int i=2;i<=sz;i++)log2[i]=log2[i>>1]+1;
	rmq_init();
	int q;scanf("%d",&q);char opt[5];int x;
	tot=n;
	while(q--){
		scanf("%s",opt);
		if(opt[0]=='G'){
			if(tot<=1)printf("%d\n",tot-1);
			else printf("%d\n",ans.Top());
		}else{
			scanf("%d",&x);
			if(mark[x])tot++;
			else tot--;
			change(x,mark[x]^=1);
		}
	}
	return 0;
}
		


你可能感兴趣的:(1095: [ZJOI2007]Hide 捉迷藏)