点了动态点分治的科技树,这道题是树形态不变的动态点分治,形态变化的话...待会补

考虑点分治过程中的这样一种结构:按递归层次把当前层的重心与上层重心互相连接,这就是点分治树,容易看出它的树高只有$O(\log_2n)$

对这棵树进行讨论,先考虑没有修改怎么做,对于点分树上的一个点$x$,我们遍历它的每个儿子$u$的子树并找到$u$的子树内的所有点到$x$的最大距离,记为$far_u$,那么$x$的所有儿子$u$的$far_u$中最大和次大加起来就是经过$x$的答案

因为有修改所以我们需要把$u$子树内的所有点到$x$的距离用一个堆存在节点$u$(不妨称此堆为堆$1$),同时我们需要把$x$的所有儿子$u$的堆$1$堆顶用一个堆存在$x$(不妨称为堆$2$),再用堆$3$存所有(堆$2$的最大值和次大值之和),此时堆$3$的堆顶就是答案

到这里,修改就变得很简单了,改堆$1$的同时更新堆$2$堆$3$即可

实现的时候如果某个节点是可用的,它的堆$2$内要有一个$0$表示路径从$x$出发,修改时也要记得加$0$或删$0$

#include<stdio.h>
#include<queue>
using namespace std;
const int inf=2147483647;
struct heap{
	priority_queue<int>h,d;
	void push(int v){h.push(v);}
	void erase(int v){d.push(v);}
	void adj(){
		while(!d.empty()&&h.top()==d.top()){
			h.pop();
			d.pop();
		}
	}
	int top(){
		adj();
		return h.top();
	}
	void pop(){
		adj();
		h.pop();
	}
	int sec(){
		int x,y;
		x=top();
		pop();
		y=top();
		push(x);
		return y;
	}
	int size(){return h.size()-d.size();}
}h1[100010],h2[100010],al;
int h[100010],to[200010],nex[200010],M;
void add(int a,int b){
	M++;
	to[M]=b;
	nex[M]=h[a];
	h[a]=M;
}
int fa_[100010][17],dep[100010];
void dfs(int x){
	for(int i=h[x];i;i=nex[i]){
		if(to[i]!=fa_[x][0]){
			fa_[to[i]][0]=x;
			dep[to[i]]=dep[x]+1;
			dfs(to[i]);
		}
	}
}
int lca(int x,int y){
	int i;
	if(dep[x]<dep[y])swap(x,y);
	for(i=16;i>=0;i--){
		if(dep[fa_[x][i]]>=dep[y])x=fa_[x][i];
	}
	if(x==y)return x;
	for(i=16;i>=0;i--){
		if(fa_[x][i]!=fa_[y][i]){
			x=fa_[x][i];
			y=fa_[y][i];
		}
	}
	return fa_[x][0];
}
int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
int siz[100010],n;
bool v[100010];
void dfs1(int fa,int x){
	n++;
	siz[x]=1;
	for(int i=h[x];i;i=nex[i]){
		if(!v[to[i]]&&to[i]!=fa){
			dfs1(x,to[i]);
			siz[x]+=siz[to[i]];
		}
	}
}
int mn,cn;
void dfs2(int fa,int x){
	int i,k;
	k=0;
	for(i=h[x];i;i=nex[i]){
		if(!v[to[i]]&&to[i]!=fa){
			dfs2(x,to[i]);
			k=max(k,siz[to[i]]);
		}
	}
	k=max(k,n-siz[x]);
	if(k<mn){
		mn=k;
		cn=x;
	}
}
void dfs3(heap&p,int s,int fa,int x){
	p.push(dis(x,s));
	for(int i=h[x];i;i=nex[i]){
		if(!v[to[i]]&&to[i]!=fa)dfs3(p,s,x,to[i]);
	}
}
int fa[100010];
int solve(int f,int x){
	n=0;
	dfs1(0,x);
	mn=inf;
	dfs2(0,x);
	x=cn;
	if(f)dfs3(h1[x],f,0,x);
	fa[x]=f;
	v[x]=1;
	h2[x].push(0);
	for(int i=h[x];i;i=nex[i]){
		if(!v[to[i]])h2[x].push(h1[solve(x,to[i])].top());
	}
	if(h2[x].size()>1)al.push(h2[x].top()+h2[x].sec());
	return x;
}
void modify(int x,int v,bool f){
	if(h2[fa[x]].size()>1)al.erase(h2[fa[x]].top()+h2[fa[x]].sec());
	if(h2[fa[x]].size()>0&&h1[x].size()>0)h2[fa[x]].erase(h1[x].top());
	f?h1[x].push(v):h1[x].erase(v);
	if(h1[x].size()>0)h2[fa[x]].push(h1[x].top());
	if(h2[fa[x]].size()>1)al.push(h2[fa[x]].top()+h2[fa[x]].sec());
}
void change(int x){
	v[x]^=1;
	if(h2[x].size()>1)al.erase(h2[x].top()+h2[x].sec());
	v[x]?h2[x].push(0):h2[x].erase(0);
	if(h2[x].size()>1)al.push(h2[x].top()+h2[x].sec());
	for(int i=x;fa[i];i=fa[i])modify(i,dis(fa[i],x),v[x]);
}
int main(){
	int n,m,i,j,x,y,sum;
	char s[5];
	scanf("%d",&n);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dep[1]=1;
	dfs(1);
	for(j=1;j<17;j++){
		for(i=1;i<=n;i++)fa_[i][j]=fa_[fa_[i][j-1]][j-1];
	}
	solve(0,1);
	scanf("%d",&m);
	sum=n;
	while(m--){
		scanf("%s",s);
		if(s[0]=='G')
			printf("%d\n",sum<2?sum-1:al.top());
		else{
			scanf("%d",&x);
			v[x]?(sum--):(sum++);
			change(x);
		}
	}
}

[BZOJ1095]捉迷藏的更多相关文章

  1. 【BZOJ1095】捉迷藏(动态点分治)

    [BZOJ1095]捉迷藏(动态点分治) 题面 BZOJ 题解 动态点分治板子题 假设,不考虑动态点分治 我们来想怎么打暴力: \(O(n)DP\)求树的最长链 一定都会.不想解释了 所以,利用上面的 ...

  2. 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏

    简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...

  3. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  4. [bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

    [bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiaji ...

  5. 【BZOJ1095】 Hide 捉迷藏

    Time Limit: 4000 ms   Memory Limit: 256 MB Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.W ...

  6. BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  7. BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...

  8. BZOJ1095: [ZJOI2007]Hide 捉迷藏【线段树维护括号序列】【思维好题】

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  9. 「BZOJ1095」[ZJOI2007] Hide 捉迷藏

    题目描述 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条 ...

随机推荐

  1. 免费的dns服务器(更换dns服务器有时可以解决某些网站(如爱奇艺访问不了的问题))

    首先百度提供的dns就是非常好用的dns,小编就把百度的dns作为首选180.76.76.76.   其次是阿里提供的dns223.5.5.5,响应速度非常的快,而且没有广告劫持.   再就是最通用的 ...

  2. 从零开始学习MXnet(四)计算图和粗细粒度以及自动求导

    这篇其实跟使用MXnet的关系不大,但对于我们理解深度学习的框架设计还是很有帮助的. 首先还是对promgramming models的一个简单介绍,这个东西实际上是在编译里面经常出现的东西,我们在编 ...

  3. zigbee ---- endpoint理解

    很多资料将其翻译为“端点”,我们不如也这么叫. 在windows上使用不同的软件进行通信,数据包到达不同的应用的方法就是通过寻找IP地址和端口号来确定某一个应用的,也就是我们所说的五元组(源IP,目的 ...

  4. HDU 2084 DP经典例子---数塔问题

    http://acm.hdu.edu.cn/showproblem.php?pid=2084 #include "iostream" #include "cstdio&q ...

  5. 【数据结构】bzoj3747Kinoman

    Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l< ...

  6. VR行业纷纷倒闭:有硬件没内容

    从去年年底开始,VR就成为了一个流行词汇,不仅是巨头公司砸钱布局,众多创业公司也纷纷投入其中.但是,一窝蜂拥入的企业基本都没有成熟的商业模式和赢利模式,只能靠融资供血.在资本寒冬中,大部分的VR企业开 ...

  7. MDK stm32 仿真

    直接选择simulator,仿真时报错 *** error 65: access violation at 0x40021000 : no 'read' permission 修改系统配置,原配置如下 ...

  8. bzoj3127/3697 [Usaco2013 Open]Yin and Yang

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3127 http://www.lydsy.com/JudgeOnline/problem.ph ...

  9. 求LCA最近公共祖先的在线倍增算法模板_C++

    倍增求 LCA 是在线的,而且比 ST 好写多了,理解起来比 ST 和 Tarjan 都容易,于是就自行脑补吧,代码写得容易看懂 关键理解 f[i][j] 表示 i 号节点的第 2j 个父亲,也就是往 ...

  10. bzoj 2748 DP

    比较裸的背包,w[i][j]代表到第I个操作的时候音量j能不能达到,然后转移就行了. /******************************************************** ...