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条双 ...
随机推荐
- Array of Doubled Pairs
Given an array of integers A with even length, return true if and only if it is possible to reorder ...
- [转帖]Java 8新特性探究(九)跟OOM:Permgen说再见吧
Java 8新特性探究(九)跟OOM:Permgen说再见吧 https://my.oschina.net/benhaile/blog/214159 need study 很多开发者都在其系统中见过“ ...
- sql sever 两数据表差异比较EXCEPT、INTERSECT
1.概念: EXCEPT主要是用来获取两个结果集的差:两个结果用EXCEPT链接,返回第一个结果集不在第二个结果集中的数据. INTERSECT主要是用来获取两个结果集的交集:两个结果用INTERSE ...
- Collection接口的子接口——Queue接口
https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html public interface Queue<E> exten ...
- sql server SQL 服务器 - RDBMS
SQL 服务器 - RDBMS --现代的 SQL 服务器构建在 RDBMS 之上. DBMS - 数据库管理系统(Database Management System) --数据库管理系统是一种可以 ...
- 机器学习-正则化(岭回归、lasso)和前向逐步回归
机器学习-正则化(岭回归.lasso)和前向逐步回归 本文代码均来自于<机器学习实战> 这三种要处理的是同样的问题,也就是数据的特征数量大于样本数量的情况.这个时候会出现矩阵不可逆的情况, ...
- 02 前端之css
---恢复内容开始--- 1.css的几种引入方式: 1.行内样式 (行内式是在标记的style属性中设定的css样式.不推荐大规模使用) <p style="color: red&q ...
- JS常见面试题总结-真实被问到的!
1.判断数据类型有几种方法 console.log(typeof 'abc') // string console.log(Object.prototype.toString.call('abc')) ...
- 大型分布式爬虫准备 scrapy + request
那些高手 爬虫好文 而我避免这些问题的方式,控制台清除所有定时 var id = setInterval(function() {}, 0); while (id--) clearInterval(i ...
- MySQL单机上多实例安装
首先安装mysql,不要启动MySQL,先配置vim /etc/my.cnf.[mysqld_multi]mysqld = /usr/bin/mysqld_safemysqladmin = /usr/ ...