写了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 捉迷藏 动态点分治+堆的更多相关文章

  1. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  2. BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治

    [题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...

  3. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)

    传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...

  4. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  5. 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆

    题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...

  6. BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...

  7. BZOJ 1095: [ZJOI2007]Hide 捉迷藏

    Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...

  8. bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习

    好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...

  9. bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双 ...

随机推荐

  1. jenkins和gitlab备份

    #把/opt目录拷贝到10.0.0.31的/tmp下. rsync  -avz  /opt  root@10.0.0.31:/tmp/ pull: rsync -avz root@10.0.0.31: ...

  2. Fiddler-打断点(bpu)

    一.断点 1.为什么要打断点? 比如一个购买的金额输入框,输入框前端做了限制大于100,那么我们测试的时候,需要测试小于100的情况下.很显然前端只能输入大于100的.这时我们可以先抓到接口,修改请求 ...

  3. 在Ubuntu上安装Hbase

    1.下载hbase2.0.5 解压缩并改名为hbase目录,放到/usr/local下(注意权限) sudo mv ~/hbase-2.0.5 /usr/local/hbase 2.修改目录所有者 / ...

  4. [LGP4859,...] 一类奇怪的容斥套DP

    漫山遍野都是fake的光影. 题目 [LGP4859] 已经没有什么好害怕的了 给定两个长度为n的数组a和b,将a中元素与b中元素配对,求满足ai>bj的配对(i,j)个数减去满足ai<b ...

  5. tp5.1中redis使用

    一.环境安装 1.下载redis,igbniary https://windows.php.net/downloads/pecl/releases/igbinary/ https://windows. ...

  6. JS基础_强制类型转换-String

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. 学习笔记--APIO 2018 二分专题 By wuvin

    前言: 在APIO 2018 Day2下午听wuvin讲二分,听了一上午的神仙,现在终于有可以听懂了. 专题: 平均边权最大 题目链接:https://www.questoj.cn/problem/3 ...

  8. 一款完美代替微信小程序原生客服消息的工具:

    一.设置:无需开发,多种回复(自动+人工)   自动回复形式有3种: 打开客服消息(用户只要和客服互动过一次,再次点击进入,会收到设置好的自动回复) 关键词回复(用户在小程序中回复某个关键词内容时,会 ...

  9. [转载]C++二维动态数组memset()函数初始化

    来源:https://blog.csdn.net/longhopefor/article/details/20994919 先说说memset函数: void *memset(void *s,int ...

  10. spring boot入门与进阶教程

    SpringBoot入门.SpringBoot进阶.Spring Cloud微服务.Spring Ecosystem 微服务相关.Spring Boot 入门 IDEA 版本.Spring Boot集 ...