BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
写了7k多,可以说是一己之力切掉了这道毒瘤题~
开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解.
由于需要支持堆的删除,所以写起来特别恶心+麻烦.
细节巨多~
#include <bits/stdc++.h>
#include <cstdio>
#include <queue>
#include <algorithm>
#define N 200004
#define setIO(s) freopen(s".in","r",stdin) // , freopen(s".out","w",stdout)
using namespace std;
int edges,n;
int hd[N],to[N<<1],nex[N<<1];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
struct Queue
{
priority_queue<int>q;
priority_queue<int>del;
void re()
{
while(!q.empty()&&!del.empty()&&q.top()==del.top()) q.pop(),del.pop();
}
void pop()
{
re();
if(!q.empty()) q.pop();
}
void push(int x)
{
re();
q.push(x);
}
int empty()
{
re();
return q.empty();
}
int size()
{
re();
return q.size()-del.size();
}
int top()
{
re();
if(!q.empty())
return q.top();
else
return -1;
}
void erase(int x)
{
re();
del.push(x);
}
}F[N],G[N],Total;
namespace tree
{
int dep[N],size[N],son[N],top[N],fa[N];
void dfs1(int u,int ff)
{
fa[u]=ff,dep[u]=dep[ff]+1,size[u]=1;
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff)
{
dfs1(to[i],u),size[u]+=size[to[i]];
if(size[to[i]]>size[son[u]]) son[u]=to[i];
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=hd[u];i;i=nex[i])
if(to[i]!=fa[u]&&to[i]!=son[u])
dfs2(to[i],to[i]);
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
return dep[x]<dep[y]?x:y;
}
int Dis(int x,int y)
{
return dep[x]+dep[y]-(dep[LCA(x,y)]<<1);
}
};
int root,sn;
int mx[N],vis[N],Fa[N],size[N],sta[N];
void dfs(int u,int ff)
{
size[u]=1;
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff&&!vis[to[i]])
dfs(to[i],u),size[u]+=size[to[i]];
}
void getroot(int u,int ff)
{
size[u]=1,mx[u]=0;
for(int i=hd[u];i;i=nex[i])
if(!vis[to[i]]&&to[i]!=ff)
getroot(to[i],u),mx[u]=max(mx[u],size[to[i]]),size[u]+=size[to[i]];
mx[u]=max(mx[u],sn-size[u]);
if(mx[u]<mx[root]) root=u;
}
void work(int u,int ff,int rt)
{
if(Fa[rt])
G[rt].push(tree::Dis(Fa[rt],u));
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff&&!vis[to[i]])
work(to[i],u,rt);
}
void calc(int u)
{
work(u,0,u);
F[u].push(0);
if(Fa[u]&&G[u].size()) F[Fa[u]].push(G[u].top());
}
void prepare(int u)
{
vis[u]=1;
calc(u);
for(int i=hd[u];i;i=nex[i])
if(!vis[to[i]])
dfs(to[i],u),sn=size[to[i]],root=0,getroot(to[i],u),Fa[root]=u,prepare(root);
if(F[u].size()>=2)
{
int a=0,b=0;
a=F[u].top(), F[u].pop();
b=F[u].top(), F[u].pop();
Total.push(a+b);
F[u].push(a), F[u].push(b);
}
}
// 开灯 (更小)
void open(int u,int key)
{
int a=0,b=0,a1=0,b1=0;
if(F[u].size()>=2)
{
a=F[u].top(),F[u].pop();
b=F[u].top(),F[u].pop();
F[u].push(a),F[u].push(b),F[u].erase(key);
if(F[u].size()>=2)
{
a1=F[u].top(),F[u].pop();
b1=F[u].top(),F[u].pop();
F[u].push(a1),F[u].push(b1);
if(a1+b1!=a+b)
{
Total.erase(a+b);
Total.push(a1+b1);
}
}
else Total.erase(a+b);
}
else F[u].erase(key);
}
void shut(int u,int key)
{
int a=0,b=0,a1=0,b1=0;
if(F[u].size()>=1)
{
if(F[u].size()>=2)
{
a=F[u].top(),F[u].pop();
b=F[u].top(),F[u].pop();
F[u].push(a),F[u].push(b),F[u].push(key);
a1=F[u].top(),F[u].pop();
b1=F[u].top(),F[u].pop();
F[u].push(a1),F[u].push(b1);
if(a1+b1!=a+b)
{
Total.erase(a+b);
Total.push(a1+b1);
}
}
else
{
a=F[u].top(),F[u].push(key);
Total.push(a+key);
}
}
else F[u].push(key);
}
// 开灯(更小)
void update1(int u)
{
open(u,0);
for(int U=u;Fa[u];u=Fa[u])
{
int dis=tree::Dis(U,Fa[u]);
if(G[u].top()==dis)
{
G[u].erase(dis);
open(Fa[u],dis);
if(!G[u].empty())
{
int a=G[u].top();
shut(Fa[u],a);
}
}
else G[u].erase(dis);
}
}
// 关灯(更大)
void update2(int u)
{
shut(u,0);
for(int U=u;Fa[u];u=Fa[u])
{
int dis=tree::Dis(U,Fa[u]);
if(G[u].top()>=dis) G[u].push(dis);
else if(G[u].empty())
{
G[u].push(dis);
shut(Fa[u],dis);
}
else
{
shut(Fa[u],dis);
open(Fa[u],G[u].top());
G[u].push(dis);
}
}
}
int main()
{
int i,j,Q;
// setIO("input");
scanf("%d",&n);
for(i=1;i<n;++i)
{
int a,b;
scanf("%d%d",&a,&b),add(a,b),add(b,a);
}
tree::dfs1(1,0),tree::dfs2(1,1);
mx[0]=sn=n,root=0,getroot(1,0),prepare(root);
scanf("%d",&Q);
for(i=1;i<=Q;++i)
{
char str[2];
scanf("%s",str);
if(str[0]=='C')
{
int u;
scanf("%d",&u);
if(sta[u]==0)
{
update1(u);
}
else
{
update2(u);
}
sta[u]^=1;
}
if(str[0]=='G')
{
if(Total.empty())
printf("-1\n");
else
printf("%d\n",Total.top());
}
}
}
BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆的更多相关文章
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏
Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...
- bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双 ...
随机推荐
- [转帖]JVM总结--JVM体系结构
JVM总结--JVM体系结构 https://blog.csdn.net/samjustin1/article/details/52215274 需要不断的学习才可以. 2016年08月15日 22: ...
- 设计模式:解释器模式(Interpreter)
为人处事是一门大学问,察言观色.听懂弦外之音都是非常重要的,老板跟你说“XX你最近表现平平啊,还得要多努力”,如果你不当回事,平常对待,可能下次就是“XX,恩,你人还是不错,平常工作也很努力,但是我想 ...
- 以石子合并为例的区间DP
区间DP,是一类具有较为固定解法的DP,一般的思路都是: first.初始化区间长度为1的情况(一般区间长度为1的较易于初始化) second. for(枚举区间长度2~n){ for(枚举左端点){ ...
- LZH的多重影分身 qduoj 思维 差分
LZH的多重影分身 qduoj 思维 差分 原题链接:https://qduoj.com/problem/591 题意 在数轴上有\(n\)个点(可以重合)和\(m\)条线段(可以重叠),你可以同时平 ...
- 版本控制器之SVN(二)
安装重启以后,在菜单栏找到TortoiseSVN程序 启动以后 点击: 填写相应的信息: 可以看到项目的相关信息 选中仓库,右键 > Browse Repository 进入如下界面: 可以打开 ...
- python-1:正则表达式(基础知识点)
1.简单匹配: \d →匹配一个数字 \w →匹配一个数字或字母 \s →匹配一个空格(包括tab等空白符) . →匹配任意字符 * →匹配任意个字符(包括0个) + →匹配至少一个字 ...
- 113、stack的优势 (Swarm20)
参考https://www.cnblogs.com/CloudMan6/p/8157391.html stack 将应用所包含的service,依赖的secret volume 等资源,以及他们之 ...
- ArcGis之popup列表字段自定义
ArcGis之popup列表字段自定义 featureLayer图层中可以使用popupTemplate属性添加弹窗. API:https://developers.arcgis.com/javasc ...
- python cv2截取不规则区域图片
知识掌握 cv2.threshold()函数: 设置固定级别的阈值应用于多通道矩阵,将灰度图像变换二值图像,或去除指定级别的噪声,或过滤掉过小或者过大的像素点. Python: cv2.thresho ...
- elastic 查询
1.match 查询 GET /_index/_search { "query": { "match": { " } } } 1.match 多条件查 ...