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条双 ...
随机推荐
- luoguP1379-八数码难题(双向bfs)
题目链接:https://www.luogu.org/problemnew/show/P1379 题意:用字符串表示八数码,求根据给定八数码得到末状态“123804765”最少的步数. 思路:这题很方 ...
- [转帖]一张图让你看懂InnoDB
一张图让你看懂InnoDB 2018年05月10日 10:02:34 灵魂自由的忙人 阅读数 299 https://blog.csdn.net/xiaoyi23000/article/details ...
- java的hashCode和equals为什么要同时重写?
原因: java规范:相等的对象必须具有相等的散列码(hashCode) 同时对于HashSet和HashMap这些基于散列值(hash)实现的类.key的判断是通过hashCode完成,且散列也是通 ...
- 禁用Win10自带截图工具快捷键(Shift+Win+S)
由于在微信之前,多年使用QQ的缘故,已经习惯了使用Ctrl+Alt+A进行截图,虽然QQ后来还专门提供了TIM(Office-QQ),但仍然渐渐的以微信为主,TIM甚至已经很少登录,之前登录也仅仅是为 ...
- 剑指Offer 1-41 代码(python实现)
今天主要写了一下offer 1-41题,余下的稍后整理 1 """ 1 镜像二叉树: 递归 """ def mirror(root): if ...
- solr学习笔记-增加mmesg4J中文分词
solr版本6.1.centos6.7.mmesg4j版本2.30 solr安装目录:/usr/local/solr-6.1.0 1.下载mmesg4j包: 地址:https://github.com ...
- 将Abp的UnitTest中的InMemory改为SQLite in memory
添加nuget包 Microsoft.EntityFrameworkCore.Sqlite 添加ServiceCollectionRegistrarSqlite public static class ...
- reduce一些方法对数组进行的处理
reduce方法我之前都整理了知识点,不懂的可以看一下我之前的知识点,这次我们是整理了一些关于用reduce方法进行的一些对于数组的处理 1. reduce()求数组项之和 var arr = [3, ...
- Linux版本显示和区别32位还是64位系统
查看已经安装的Linux版本信息 1.cat /etc/issue 查看版本 [root@master master]# cat /etc/issue \S Kernel \r on an \m 2. ...
- 26、Nginx Uwsgi代理
1.Uwsgi代理基本概述 cgi.fastcgi.wsgi.uwsgi python框架 Django是一个开放源代码的web的框架 Flask是一个使用python编写的轻量级web应用框架 2 ...