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

捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩
捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋
子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的
时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两

Description

  捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩
捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋
子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的
时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两
个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房
间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的
距离。

Input

  第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b,
表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如
上文所示。

Output

  对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关
着灯的,输出0;若所有房间的灯都开着,输出-1。

Sample Input

8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G

Sample Output

4
3
3
4

HINT

对于100%的数据, N ≤100000, M ≤500000。


题目大意

给定一棵树,每个点的颜色不是黑色就是白色,开始所有点的颜色都是黑色,要求支持两个操作:

  1. 翻转一个点的颜色
  2. 询问最远的黑点对的距离。如果只有1个黑点,那么输出0,如果没有黑点,输出-1。

  由于有多次询问,所以不可能暴力求最长链。

  如何快速处理最长链?于是想到了点分治。

  现在的任务是让点分治支持修改操作。

  因为最长距离不可加减,所以只能通过维护分治中心的各子树中,深度最大的点,然后取前两大更新答案。

  因此,每个点维护两个堆,一个堆维护点分树上它的子树中深度最大的点的深度,一个堆维护在点分树上它的子树中所有点到它的父分治中心的距离。

  除此之外,还要开一个全局堆维护答案。

  对于修改操作,就是删除元素再插入元素,自己画画图就能想清楚(明明是yyf扯不清楚)。

  问题是怎么让堆支持删除?再开个堆打标记就好了。

  还有一个问题,如何求树上两点间的距离?两点的深度减去它们LCA的深度的两倍,求LCA用st表。

Code

  1 /**
  2  * bzoj
  3  * Problem#1095
  4  * Accepted
  5  * Time: 13356ms
  6  * Memory: 159584k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11 const signed int inf = (signed) (~0u >> 1) - 1;
 12
 13 typedef class Node {
 14     public:
 15         int val;
 16         Node *l, *r;
 17
 18         Node(int val = 0, Node* l = NULL, Node* r = NULL):val(val), l(l), r(r) {        }
 19 }Node;
 20
 21 Node* merge(Node* a, Node* b) {
 22     if(!a)    return b;
 23     if(!b)    return a;
 24     if(a->val < b->val)    swap(a, b);
 25     a->r = merge(a->r, b);
 26     swap(a->l, a->r);
 27     return a;
 28 }
 29
 30 #define Limit 10000000
 31 Node pool[Limit];
 32 Node *top = pool;
 33
 34 Node* newnode(int x) {
 35     if(top >= pool + Limit)
 36         return new Node(x, NULL, NULL);
 37     top->val = x;
 38     return top++;
 39 }
 40
 41 #define clr(rt, dr) while(rt && dr && dr->val == rt->val)    rt = merge(rt->l, rt->r), dr = merge(dr->l, dr->r)
 42 typedef class Heap {
 43     public:
 44         int s;
 45         Node* rt;
 46         Node* dr;
 47
 48         Heap():s(0), rt(NULL), dr(NULL) {        }
 49
 50         int top() {
 51             if(!rt)    return -1;
 52             return rt->val;
 53         }
 54
 55         int sectop() {
 56             if(!rt)    return -inf;
 57             clr(rt->l, dr);
 58             clr(rt->r, dr);
 59             int lv = (rt->l) ? (rt->l->val) : (-inf), rv = (rt->r) ? (rt->r->val) : (-inf);
 60             return (lv > rv) ? (lv) : (rv);
 61         }
 62
 63         void pop() {
 64             rt = merge(rt->l, rt->r);
 65             clr(rt, dr);
 66         }
 67
 68         void insert(int x) {
 69             if(x < 0)    return;
 70             s++;
 71             rt = merge(rt, newnode(x));
 72             clr(rt, dr);
 73         }
 74
 75         void remove(int x) {
 76             if(x < 0)    return;
 77             s--;
 78             dr = merge(dr, newnode(x));
 79             clr(rt, dr);
 80         }
 81
 82         int size() {
 83             return s;
 84         }
 85 }Heap;
 86
 87 const int N = 1e5 + 5;
 88
 89 int n, m, n2;
 90 vector<int> *g;
 91 Heap *dtg, *dtf, gol;
 92 int *siz, *fag, *dep, *erl;
 93 int *Log2, *in;
 94 boolean *vis, *ison;
 95
 96 inline void init() {
 97     scanf("%d", &n), n2 = n << 1;
 98     g = new vector<int>[(n + 1)];
 99     dtg = new Heap[(n + 1)];
100     dtf = new Heap[(n + 1)];
101     in = new int[(n + 1)];
102     siz = new int[(n + 1)];
103     fag = new int[(n + 1)];
104     dep = new int[(n + 1)];
105     erl = new int[(n2 + 1)];
106     Log2 = new int[(n2 + 1)];
107     vis = new boolean[(n + 1)];
108     ison = new boolean[(n + 1)];
109     fill(vis + 1, vis + n + 1, false);
110     fill(ison + 1, ison + n + 1, false);
111     for(int i = 1, u, v; i < n; i++) {
112         scanf("%d%d", &u, &v);
113         g[u].push_back(v);
114         g[v].push_back(u);
115     }
116 }
117
118 int cerl = 0;
119 void dfs1(int p, int fa) {
120     erl[++cerl] = p;
121     in[p] = cerl;
122     dep[p] = dep[fa] + 1;
123     for(int i = 0; i < (signed)g[p].size(); i++) {
124         int e = g[p][i];
125         if(e == fa)    continue;
126         dfs1(e, p);
127         erl[++cerl] = p;
128     }
129 }
130
131 #define bzmax 19
132 int st[19][N << 1];
133 inline void init_st() {
134     Log2[1] = 0, dep[0] = 0;
135     for(int i = 2; i <= n2; i++)
136         Log2[i] = Log2[i >> 1] + 1;
137     dfs1(1, 0);
138
139     for(int i = 1; i < n2 - 1; i++)
140         st[0][i] = (dep[erl[i]] < dep[erl[i + 1]]) ? (erl[i]) : (erl[i + 1]);
141     for(int j = 1; j < bzmax; j++)
142         for(int i = 1, a, b; i + (1 << j) < n2; i++) {
143             a = st[j - 1][i], b = st[j - 1][i + (1 << (j - 1))];
144             st[j][i] = (dep[a] < dep[b]) ? (a) : (b);
145         }
146 }
147
148 inline int Lca(int u, int v) {
149     int l = in[u], r = in[v], len, a, b;
150     if(l > r)    swap(l, r);
151     len = Log2[r - l + 1];
152     a = st[len][l], b = st[len][r - (1 << len) + 1];
153     return (dep[a] < dep[b]) ? (a) : (b);
154 }
155
156 inline int dist(int u, int v) {
157     int lca = Lca(u, v);
158     return dep[u] + dep[v] - (dep[lca] << 1);
159 }
160
161 void dfs2(int p, int fa) {
162     siz[p] = 1;
163     for(int i = 0; i < (signed)g[p].size(); i++) {
164         int e = g[p][i];
165         if(e == fa || vis[e])    continue;
166         dfs2(e, p);
167         siz[p] += siz[e];
168     }
169 }
170
171 void dfs3(int p, int fa, int& cov, int& G, int& maxv) {
172     int cmp = cov - siz[p];
173     for(int i = 0; i < (signed)g[p].size(); i++) {
174         int e = g[p][i];
175         if(e == fa || vis[e])    continue;
176         dfs3(e, p, cov, G, maxv);
177         cmp = (siz[e] > cmp) ? (siz[e]) : (cmp);
178     }
179     if(cmp < maxv)
180         maxv = cmp, G = p;
181 }
182
183 void dfs4(int p, int fa, int dep, int G, int fG) {
184     if(fG)    dtf[G].insert(dist(p, fG));
185     for(int i = 0; i < (signed)g[p].size(); i++) {
186         int e = g[p][i];
187         if(e == fa || vis[e])    continue;
188         dfs4(e, p, dep + 1, G, fG);
189     }
190 }
191
192 #define get_val(h)    (h.size() <= 1) ? ((h.size() == 1) ? (0) : (-1)) : (h.top() + h.sectop())
193 int dividing(int p, int fag) {
194     dfs2(p, 0);
195     int G, maxv = inf, sG;
196     dfs3(p, 0, siz[p], G, maxv);
197     vis[G] = true, ::fag[G] = fag;
198     dfs4(G, 0, 0, G, fag);
199     dtg[G].insert(0);
200     for(int i = 0; i < (signed)g[G].size(); i++) {
201         int e = g[G][i];
202         if(vis[e])    continue;
203         sG = dividing(e, G);
204         dtg[G].insert(dtf[sG].top());
205     }
206     gol.insert(get_val(dtg[G]));
207     return G;
208 }
209
210 void turn_on(int p) {
211     int G = p, oldt = 0, newt = -1;
212     ison[p] = true;
213     while (G) {
214         if(oldt != newt) {
215             gol.remove(get_val(dtg[G]));
216             dtg[G].remove(oldt);
217             if(~newt)    dtg[G].insert(newt);
218             gol.insert(get_val(dtg[G]));
219         }
220         if (fag[G]) {
221             oldt = dtf[G].top();
222             dtf[G].remove(dist(p, fag[G]));
223             newt = dtf[G].top();
224         }
225         G = fag[G];
226     }
227 }
228
229 void turn_off(int p) {
230     int G = p, oldt = -1, newt = 0;
231     ison[p] = false;
232     while (G) {
233         if(oldt != newt) {
234             gol.remove(get_val(dtg[G]));
235             if(~oldt)    dtg[G].remove(oldt);
236             dtg[G].insert(newt);
237             gol.insert(get_val(dtg[G]));
238         }
239         if(fag[G]) {
240             oldt = dtf[G].top();
241             dtf[G].insert(dist(p, fag[G]));
242             newt = dtf[G].top();
243         }
244         G = fag[G];
245     }
246 }
247
248 inline void solve() {
249     scanf("%d", &m);
250     char buf[10];
251     int x;
252     while (m--) {
253         scanf("%s", buf);
254         if(buf[0] == ‘G‘) {
255             int x = gol.top();
256             printf("%d\n", x);
257         } else {
258             scanf("%d", &x);
259             if(ison[x])
260                 turn_off(x);
261             else
262                 turn_on(x);
263         }
264     }
265 }
266
267 int main() {
268     init();
269     init_st();
270     dividing(1, 0);
271     solve();
272     return 0;
273 }

原文地址:https://www.cnblogs.com/yyf0309/p/8283214.html

时间: 2024-07-29 14:44:46

bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆的相关文章

BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆

题目大意:给定一棵树,一开始每个点都是黑点,多次改变某个点的状态或询问距离最远的两个黑点的距离 <珍爱生命远离STL可是我还是可耻地用了STL系列> 传说中的动态树分治...其实并没有那么神嘛= = ↑别听这傻瓜瞎说这货被STL卡了一天QAQ 我们把分治过程中遍历过的重心都连起来 上一层的重心链接下一层的重心 可以得到一棵新的树 下面我们开始讨论这棵新树 显然这棵树的高度不会超过O(logn) 然后我们每个节点开两个堆 第一个堆记录子树中所有节点到父亲节点的距离 第二个堆记录所有子节点的堆顶

bzoj 1095 [ZJOI2007]Hide 捉迷藏 动态点分治+堆

题面 题目传送门 解法 挺恶心的题 考虑动态点分治,先建出点分树 然后每一个点开两个堆,分别为\(a,b\) \(a_i\)表示点分树上\(i\)子树中所有节点在原树上和点分树中\(i\)父亲的距离,\(b_i\)表示点分树中\(i\)所有儿子的堆顶 再开一个堆\(ans\),存每一个\(b_i\)最大和次大值的和 在修改的时候,分两种情况考虑 但是本质都是一样的,就是在点分树上不断爬,爬到根为止,然后对当前点和父亲的\(a,b\)进行删除和加入 细节比较多,需要注意 重点:传入一个结构体参数的

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

[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激

[BZOJ]1095 Hide捉迷藏(ZJOI2007)

一道神题,两种神做法. Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯

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

好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状(菊花啊..链啊..扫把啊..)这就导致各种方法都会被卡 于是通过每次找重心保证最大深度 动态怎么解决呢? 不妨考虑线段树是二分的固态版本(只可意会),那么我们把每次找到的重心固定下来长成一棵树就可以把点分治凝固(不可言传) 原来点分治该维护什么现在就维护什么... (事实上我并没有写过静态点分治..

【BZOJ1095】【ZJOI2007】捉迷藏 [动态点分治]

捉迷藏 Time Limit: 40 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏. 他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达. 游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯. 在起初

BZOJ 4012 HNOI2015 开店 动态树分治+二分

题目大意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和,强制在线 没记错的话这题我知道的有三种解法来着? (茴香豆的茴有四种写法泥萌知道嘛-? 1.线段树维护虚树 2.点分治+线段树 3.分块 第一种方法我不知道在线怎么搞= = (我并不知道怎么在虚树上进行点定位 第三种方法貌似内存过不去? 于是果断点分治+线段树 写完发现内存还是炸了= = O(nlog2n)的内存说什么也过不去啊= = 后来发现既然维护的是和不是最值那还要线段树干嘛= = 直接开

点分治+动态点分治

最近好颓废,什么都学不进去... 感谢两篇:AKMer - 浅谈树分治  言简意赅 LadyLex - 点分治&动态点分治小结  讲解+例题,学到很多东西 点分治 动态点分治 ~ 点分治 ~ 经常遇见一类树上的计数题,问的是在某些条件下,选择一些点的方案数 若对于每个点的统计都需要遍历以其为根节点的子树,普通的做法就是$O(n^2)$的,在很多时候是不满足要求的 而这是点分治的专长 点分治是这样进行的: 1. 找到当前树的重心 2. 将重心及重心连出的边全部删去,那么就能将原来的树分割成森林 3

bzoj 1095: [ZJOI2007]Hide 捉迷藏

Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋 子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的 时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要 求打开某个房间的电灯或者关闭某个房间