bzoj1095: [ZJOI2007]Hide 捉迷藏
Posted sssy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1095: [ZJOI2007]Hide 捉迷藏相关的知识,希望对你有一定的参考价值。
题目链接
题解
建出点分树,每次修改一个结点只影响它到树根的一条链暴力修改
实现的时候用三层带修改堆来维护
B.维护每个重心存所有子树到其点分树父亲节点de距离
C.维护子树中的点到根的距离 ,我们可以用子节点的B来更新它
A.全局一个堆,维护答案最大值,就是最长链+次长连
每次修改向上改就行,因为树高时log的复杂度
(O(nlogn +qlog^2n))
rmq lca卡卡常,本题有更优做法..以后再说吧
代码
/*
每次修改一个结点只影响它到树根的一条链
这题具体实现的时候要维护三层堆
B.维护每个重心存所有子树到其点分树父亲节点de距离
C.维护子树中的点到根的距离 ,我们可以用子节点的B来更新它
A.全局一个堆,维护答案最大值,
*/
#include<queue>
#include<cstdio>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
return x;
}
#define INF 998244353
const int maxn = 300007;
int son[maxn],f[maxn],mn[maxn << 1][25],root,tot;
struct node {
int u,v,next;
} edge[maxn << 1];
int head[maxn],num = 0;
void add_edge(int u,int v) {
edge[++ num].v = v;edge[num].next = head[u];head[u] = num;
}
int n;
int lg[maxn << 1],dfn;// = 0;
bool col[maxn];
struct Heap {
std::priority_queue<int>A,B;
void push(int x) { A.push(x); }
void erase(int x) { B.push(x); }
void pop() { while(B.size() && A.top() == B.top()) A.pop(),B.pop(); A.pop(); }
int top() {
while(B.size() && A.top() == B.top()) A.pop(),B.pop();
return A.top();
}
int size() { return A.size() - B.size(); }
int retop() { if(size() < 2) return 0;int x = top();pop();int ret = top();push(x);return ret;}
} b[maxn],c[maxn],ans;
void insert(Heap &s) {if(s.size() > 1)ans.push(s.top() + s.retop());}
void dele(Heap &s) {if(s.size() > 1) ans.erase(s.top() + s.retop());}
int pos[maxn],deep[maxn];
void dfs_rmq (int x,int fa) {
mn[pos[x] = ++ dfn][0] = deep[x] ;
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v;
if(v == fa)continue;
deep[v] = deep[x] + 1;
dfs_rmq(v,x);
mn[++ dfn][0] = deep[x]; //访问完子树后加上Qwq-
}
}
int lca(int x,int y) {
x = pos[x];y = pos[y];
if(y < x) std::swap(x,y);
int k = lg[y - x + 1];
return std::min(mn[x][k],mn[y - (1 << k) + 1][k]);
}
inline int dis(int x,int y) {
return deep[x] + deep[y] - 2 * lca(x,y);
}
bool vis[maxn];int fa[maxn];
void get_root(int x,int fa) {
son[x] = 1; f[x] = 0;
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v;
if(v == fa || vis[v]) continue;
get_root(v,x);
son[x] += son[v];f[x] = std::max(f[x],son[v]);
}
f[x] = std::max(f[x],tot - son[x]);
if(f[x] < f[root]) root = x;
}
void get(int x,int Fa,int rt) {
b[root].push(dis(x,fa[root]));
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v; if(v == Fa || vis[v]) continue;
get(v,x,rt);
}
}
void build(int x,int Fa) {
fa[x] = Fa;vis[x] = 1;
c[x].push(0);
get(x,0,Fa);
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v;
if(!vis[v] && v != Fa) {
tot = son[edge[i].v];root = 0;f[0] = INF;
get_root(edge[i].v,x);
v = root;
build(root,x);
c[x].push(b[v].top());
}
}
insert(c[x]);
}
void turn(int x,bool type) {
dele(c[x]);
if(type) c[x].erase(0);
else c[x].push(0);
insert(c[x]);
for(int i = x;i;i = fa[i]) {
dele(c[fa[i]]);
//printf("%d ",i);
if(b[i].size()) c[fa[i]].erase(b[i].top());
if(type)b[i].erase(dis(x,fa[i])); else b[i].push(dis(x,fa[i]));
if(b[i].size()) c[fa[i]].push(b[i].top());
insert(c[fa[i]]);
}
//puts("");
}
int main() {
n = read();
for(int u,v,i = 1;i < n;++ i) {
u = read(),v = read();
add_edge(u,v);add_edge(v,u);
}
dfs_rmq(1,0);
for(int i = 2;i <= dfn;++ i) lg[i] = lg[i >> 1] + 1;
for(int i = 1;i <= lg[dfn];++ i)
for(int j = dfn - (1 << i - 1);j;-- j)
mn[j][i] = std::min(mn[j][i - 1],mn[j + (1 << i - 1)][i - 1]);
f[0] = INF; root = 0; tot = n;
get_root(1,0);
build(root,0);
char opt[10];
int Q = read();
int sum = n;
for(;Q --;) {
scanf("%s",opt + 1);
if(opt[1] == 'C') {
int asd = read();
if(col[asd]) {turn(asd,0); sum ++;col[asd] = 0;}
else {turn(asd,1);sum --;col[asd] = 1;}
}
else {
if(sum == 1)puts("0");
else if(!sum)puts("-1");
else printf("%d
",ans.top());
}
}
return 0;
}
以上是关于bzoj1095: [ZJOI2007]Hide 捉迷藏的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1095[ZJOI2007]Hide 捉迷藏 动态树分治+堆