[BZOJ]1095 捉迷藏 动态点分治(点分树)
来源:互联网 发布:纸上数据如何快速录入 编辑:程序博客网 时间:2024/05/16 11:35
1095: [ZJOI2007]Hide 捉迷藏
Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 4152 Solved: 1756
[Submit][Status][Discuss]
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。
题解
啊总算A了这道动态点分治了, 感觉点分树这个名字好高大上的样子…
相比于原来的点分, 动态点分治是建了一棵点分树, 每个重心向它子树里下一层重心连边, 就成了一棵点分树, 感觉跟支配树的构造有点相似. 由于重心所以树高是log级别的, 所以暴力跳支配树fa.
第一次写引用了黄学长的代码…
顺便粘一下hzwer的题解.
一开始写的可并堆感觉自己快炸了…
其实这种做法不难。。。就是代码长。。。
把每次分治的重心连成一棵树,树的深度是logn,每次修改一个结点只影响它到树根的一条链
这题具体实现的时候要维护三层堆
C.每个重心存所有子树到其距离
B.每个重心存各个子树最大值,即子结点堆C的最大值
A.全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
树上距离用rmq来求比较优越2333
代码还是很清晰的, 虽然有180行….
#include<stdio.h>#include<queue>#include<algorithm>#define Boc register char#define Acce register int#define Prio priority_queue<int> using namespace std;const int P = 22;const int inf = 1e9 + 7;const int maxn = 1e5 + 5;const int dblmaxn = 2e5 + 10;int n, num, tot, idx, sum, root, T;char ss[2];bool vis[maxn], sta[maxn];int st[P][dblmaxn], lg[dblmaxn], in[maxn], h[maxn], dep[maxn], f[maxn], fa[maxn], siz[maxn], pw[P];inline const int read(){ Acce x = 0; Boc ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x;}struct edge{ int nxt, v; }e[dblmaxn];struct heap{ int fir, sec; Prio A, B; inline void push(int x) { A.push(x); } inline void erase(int x) { B.push(x); } inline void pop() { while(B.size() && A.top() == B.top()) A.pop(), B.pop(); A.pop(); } inline int top() { while(B.size() && A.top() == B.top()) A.pop(), B.pop(); return (A.size()) ? A.top() : 0; } inline int size() { return A.size() - B.size();} inline int stop() { if (size() < 2) return 0; fir = top(); pop(); sec = top(); push(fir); return sec; }}A, B[maxn], C[maxn];inline void add(int u, int v){ e[++ num].v = v, e[num].nxt = h[u], h[u] = num; e[++ num].v = u, e[num].nxt = h[v], h[v] = num;}void dfs(int u, int tfa){ in[u] = ++ idx; st[0][idx] = dep[u]; for (int i = h[u]; i; i = e[i].nxt) { if (e[i].v == tfa) continue; dep[e[i].v] = dep[u] + 1; dfs(e[i].v, u); st[0][++ idx] = dep[u]; }}void getrt(int u, int tfa){ siz[u] = 1, f[u] = 0; for (int i = h[u]; i; i = e[i].nxt) { if (e[i].v == tfa || vis[e[i].v]) continue; getrt(e[i].v, u); siz[u] += siz[e[i].v]; f[u] = max(f[u], siz[e[i].v]); } f[u] = max(f[u], sum - siz[u]); if (f[u] < f[root]) root = u;}void divi(int u, int dfa){ fa[u] = dfa, vis[u] = true; for (int i = h[u]; i; i = e[i].nxt) { if (vis[e[i].v]) continue; sum = siz[e[i].v], root = 0; getrt(e[i].v, u), divi(root, u); }}inline int query(int u, int v){ u = in[u], v = in[v]; if (u > v) swap(u, v); int len = lg[v - u + 1]; return min(st[len][u], st[len][v - pw[len] + 1]);}inline int dis(int u, int v){ return dep[u] + dep[v] - 2 * query(u, v); }inline void turn_off(int u){ B[u].push(0); if (B[u].size() == 2) A.push(B[u].top()); int v = u; while (fa[u]) { int f = fa[u], D = dis(f, v), tmp = C[u].top(); C[u].push(D); if (D > tmp) { int mx = B[f].top() + B[f].stop(), size = B[f].size(); if (tmp) B[f].erase(tmp); B[f].push(D); int now = B[f].top() + B[f].stop(); if (now > mx) { if (size >= 2) A.erase(mx); //means mx has contributed to A if (B[f].size() >= 2) A.push(now); //now } } u = f; }}inline void turn_on(int u){ if (B[u].size() == 2) A.erase(B[u].top()); B[u].erase(0); int v = u; while (fa[u]) { int f = fa[u], D = dis(f, v), tmp = C[u].top(); C[u].erase(D); if (D == tmp) { int mx = B[f].top() + B[f].stop(), size = B[f].size(); B[f].erase(D); if(C[u].top()) B[f].push(C[u].top()); int now = B[f].top() + B[f].stop(); if(now < mx) { if(size >= 2) A.erase(mx); if(B[f].size() >= 2) A.push(now); } } u = f; }}inline void init(){ pw[0] = 1; for (int i = 1; i < P; ++ i) pw[i] = pw[i - 1] << 1; lg[0] = -1; for (int i = 1; i < dblmaxn; ++ i) lg[i] = lg[i >> 1] + 1;}int main(){ init(); n = read(); int u, v; for (Acce i = 1; i < n; ++ i) u = read(), v = read(), add(u, v); dfs(1, 0); for (Acce i = 1; i <= lg[idx]; ++ i) for (Acce j = 1; j + pw[i] - 1 <= idx; ++ j) st[i][j] = min(st[i - 1][j], st[i - 1][j + pw[i - 1]]); f[root = 0] = inf, sum = n; getrt(1, 0), divi(root, 0); for (Acce i = 1; i <= n; ++ i) C[i].push(0); for (Acce i = 1; i <= n; ++ i) turn_off(i), tot ++; T = read(); for (Acce i = 1; i <= T; ++ i) { scanf("%s", ss); if (ss[0] == 'C') { int x = read(); if (sta[x]) turn_off(x), tot ++; else turn_on(x), tot --; sta[x] ^= 1; } else { if(tot <= 1) printf("%d\n", tot - 1); else printf("%d\n", A.top()); } }}
- [BZOJ]1095 捉迷藏 动态点分治(点分树)
- BZOJ 1095 ZJOI 2007 Hide 捉迷藏 动态点分治
- bzoj 1095: [ZJOI2007]Hide 捉迷藏 (动态点分治)
- BZOJ 1095 Hide 捉迷藏 详解(动态点分治 堆维护)
- 【BZOJ1095】捉迷藏,动态点分治
- BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆
- 【BZOJ 1095】[ZJOI2007]Hide 捉迷藏 动态树分治
- bzoj 1095: [ZJOI2007]Hide 捉迷藏 动态树分治+堆
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态树分治
- BZOJ1095 [ZJOI2007]捉迷藏 动态点分治
- [动态点分治] BZOJ1095: [ZJOI2007]Hide 捉迷藏
- 动态点分治:bzoj 3730,bzoj 1095
- [bzoj1095][ZJOI2007]Hide 捉迷藏(动态点分治)
- bzoj1095 Hide 捉迷藏 动态点分治+堆 (附动态点分治详解)
- bzoj-1095 Hide 捉迷藏
- bzoj 3730: 震波 (动态点分治)
- bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治+树上ST表)
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏【动态树分治】
- mysql建表语句二
- log4j配置文件详解
- 安卓EditText调用输入法的搜索按钮
- linux学习总结
- 异常测试实践与梳理 (上):功能异常
- [BZOJ]1095 捉迷藏 动态点分治(点分树)
- TOMCAT服务器配置域名
- svn连接不上服务器
- HDU_2008数值统计
- 利用canvas实现前端压缩图片
- showDOC工具安装及使用(centos5.5低版本)apache作为服务器
- jedis操作redis
- laravel框架提示Call to undefined function IlluminateEncryptionopenssl_encrypt()怎么解决
- Android安卓——数据存储之数据库存储