码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1095: [ZJOI2007]Hide 捉迷藏

时间:2018-07-01 11:56:40      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:inf   www.   最大值   zjoi   pos   ref   --   else   clu   

题目链接

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\n",ans.top()); 
        } 
    } 
    return 0; 
} 

bzoj1095: [ZJOI2007]Hide 捉迷藏

标签:inf   www.   最大值   zjoi   pos   ref   --   else   clu   

原文地址:https://www.cnblogs.com/sssy/p/9249369.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!