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条双 ...
随机推荐
- PTA(Basic Level)1028.人口普查
某城镇进行人口普查,得到了全体居民的生日.现请你写个程序,找出镇上最年长和最年轻的人. 这里确保每个输入的日期都是合法的,但不一定是合理的--假设已知镇上没有超过 200 岁的老人,而今天是 2014 ...
- 小记---------破解idea2018.3.6 转载
一.进入idea官网选择想要下载的版本 官网版本选择页面: https://www.jetbrains.com/idea/download/other.html IntelliJ IDEA 分为两 ...
- 在 sys.servers 中找不到服务器 '10.0.2.13'。请验证指定的服务器名称是否正确。
工作中,因为需要,搭建同事的程序模块,附加了从同事那里拷过来的该程序使用的库.(C#.C/S..Net Framework4.0 .WCF.Win10.SQL Server 2014.VS2015) ...
- Luogu P3520 [POI2011]SMI-Garbage
题目 把要变边权的边拿出来找欧拉回路就行了.正确性显然,因为一条边经过两次相当于对欧拉回路度数的奇偶性没有影响. 然后把一个个小环输出即可,具体的我也不知道怎么输,题目没讲清楚,我按着题解的来的. # ...
- 2019中山纪念中学夏令营-Day2[JZOJ]
博客的开始,先聊聊代码实现: 每次比赛以后,要有归纳错误的习惯. 错误小结: 1.读入:scanf(“%c”)会读入回车和空格,但cin不会. 2.对于二维数组的输入,不能把m,n搞混了,会引起严重的 ...
- redis在php中实际应用-hash
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. 目录: 1.批量赋值:hmset,hmget,hgetall 可用于存储一条条数据,即一个 ...
- six库 解决python2的项目如何能够完全迁移到python3
six库 解决python2的项目如何能够完全迁移到python3 SIX是用于python2与python3兼容的库. 它存在的目的是为了拥有无需修改即可在Python 2和Python 3上同时工 ...
- HTML(上)
目录 HTML(上) 浏览器 HTML 什么是HTML HTML的作用 编写HTML的规范 HTML结构 HTML常用标签 HTML标签速记 HTML(上) 浏览器 浏览器也是一个客户端 #这是一个服 ...
- Redis利用Pipeline加速查询速度的方法
1. RTT Redis 是一种基于客户端-服务端模型以及请求/响应协议的TCP服务.这意味着通常情况下 Redis 客户端执行一条命令分为如下四个过程: 发送命令 命令排队 命令执行 返回结果 客户 ...
- docker 配置私有仓库
1.使用docker 命令: 1.准备两台虚拟机,这里使用的是centos7,两台使用yum install docker 安装docker; 2.给两台虚拟机设置固定ip: 进入到虚拟机内 敲入命令 ...