[BZOJ1095]捉迷藏
点了动态点分治的科技树,这道题是树形态不变的动态点分治,形态变化的话...待会补
考虑点分治过程中的这样一种结构:按递归层次把当前层的重心与上层重心互相连接,这就是点分治树,容易看出它的树高只有$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]捉迷藏的更多相关文章
- 【BZOJ1095】捉迷藏(动态点分治)
[BZOJ1095]捉迷藏(动态点分治) 题面 BZOJ 题解 动态点分治板子题 假设,不考虑动态点分治 我们来想怎么打暴力: \(O(n)DP\)求树的最长链 一定都会.不想解释了 所以,利用上面的 ...
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- [bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治
[bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiaji ...
- 【BZOJ1095】 Hide 捉迷藏
Time Limit: 4000 ms Memory Limit: 256 MB Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.W ...
- BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- BZOJ1095: [ZJOI2007]Hide 捉迷藏【线段树维护括号序列】【思维好题】
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- 「BZOJ1095」[ZJOI2007] Hide 捉迷藏
题目描述 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条 ...
随机推荐
- ACM模板~求第k短路 ~~~A*+Dijkstra
#include <map> #include <set> #include <cmath> #include <ctime> #include < ...
- eclipse中的debug按钮组突然找不到了,找回方法
- 计算1-1/x+1/x*x
// algo1-1.cpp 计算1-1/x+1/x*x. #include<stdio.h> #include<sys/timeb.h> void main() { time ...
- [USACO1.3]虫洞
Luogu链接 题目描述 农夫约翰爱好在周末进行高能物理实验的结果却适得其反,导致N个虫洞在农场上(2<=N<=12,n是偶数),每个在农场二维地图的一个不同点. 根据他的计算,约翰知道他 ...
- centos 防火墙关闭/开启
从配置菜单关闭防火墙是不起作用的,索性在安装的时候就不要装防火墙查看防火墙状态:/etc/init.d/iptables status暂时关闭防火墙:/etc/init.d/iptables stop ...
- 【洛谷 P1653】 猴子 (并查集)
题目链接 没删除调试输出,原地炸裂,\(80\)->\(0\).如果你要问剩下的\(20\)呢?答:数组开小了. 这题正向删边判连通性是很不好做的,因为我们并不会并查集的逆操作.于是可以考虑把断 ...
- ubuntu设置默认python版本
原文:https://www.cnblogs.com/johnny1024/p/8400511.html ··· ubuntu 16.04本身是自带python的,他本身是自带2.X和3.X,两个版本 ...
- c 語言 控制碼
source code #include <stdio.h> int main() { char *test = "ABC\x41\n"; printf("s ...
- locust===Writing a locustfile
The Locust class A locust class represents one user (or a swarming locust if you will). Locust will ...
- appium===元素定位
一.常用识别元素的工具 uiautomator:Android SDK自带的一个工具,在tools目录下 monitor:Android SDK自带的一个工具,在tools目录下 Appium Ins ...