bzoj 1095: [ZJOI2007]Hide 捉迷藏

Posted Achen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1095: [ZJOI2007]Hide 捉迷藏相关的知识,希望对你有一定的参考价值。

传送门

传送中的动态点分治。

就是在点分治的同时把分治树建立出来,然后每个节点用数据结构维护节点内的内容。

这道题用了三个set,(貌似也可以用6个堆,每个set用一个ins堆和一个del堆来代替),一个维护当前rt的答案,就是当前点作为这一块联通块的根时往下能到达黑点的长度。一个维护当前rt对于它在分治树上的父亲的贡献,也就是当前rt里每一个点和当前rt在分治树上的父亲间的距离(用lca求)。再全局开一个set维护每个rt中可以算作答案的最大值和次大值的和。

Achen不仅智力低下码力也这么低下。。

技术分享图片
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
const int N=100007,M=500007;
typedef long long LL;
using namespace std;
int n,Q,clo[N];
char o[10];

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!=-&&(ch<0||ch>9)) ch=getchar();
    if(ch==-) f=-1,ch=getchar();
    for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f;
}

int ecnt,fir[N],nxt[N<<1],to[N<<1];
void add(int u,int v) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}

int f[N][17],R[N];
int get_lca(int x,int y) {
    if(R[x]<R[y]) swap(x,y);
    int rs=0;
    for(int i=16;i>=0;i--) 
        if(R[f[x][i]]>=R[y]) {
            x=f[x][i];
            rs+=(1<<i); 
        }
    if(x==y) return rs;
    for(int i=16;i>=0;i--) 
        if(f[x][i]!=f[y][i]) {
            x=f[x][i]; y=f[y][i];
            rs+=(1<<(i+1));
        }
    return rs+2;
}

void dfs1(int x,int fa) {
    f[x][0]=fa;
    R[x]=R[fa]+1;
    for(int i=1;i<17;i++) f[x][i]=f[f[x][i-1]][i-1];
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        dfs1(to[i],x);
    }
} 

int nowsz,nf[N],vis[N],rt,sz[N],mxson[N],g[N][2];
void get_root(int x,int fa) {
    sz[x]=mxson[x]=1;
    for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]&&to[i]!=fa) {
        get_root(to[i],x);
        sz[x]+=sz[to[i]];
        mxson[x]=max(mxson[x],sz[to[i]]);
    }
    mxson[x]=max(mxson[x],nowsz-sz[x]);
    if(!rt||mxson[x]<mxson[rt]) rt=x;
}

struct node{
    int x,len;
    node(){}
    node(int x,int len):x(x),len(len){}
    friend bool operator <(const node &A,const node&B) {
        return A.len>B.len||(A.len==B.len&&A.x<B.x);
    } 
}tpn,tpt;

struct Node{
    int fi,se;
    Node(){}
    Node(int fi,int se):fi(fi),se(se){}
    friend bool operator <(const Node &A,const Node&B) {
        return A.fi+A.se>B.fi+B.se;
    } 
}tpN;

set<node>s[N];
multiset<int>t[N];
multiset<Node>mx;

#define IT set<node>::iterator 
#define It multiset<Node>::iterator
int ec,F[N],nx[N],tt[N];
void ADD(int u,int v) {
    nx[++ec]=F[u]; F[u]=ec; tt[ec]=v;
}
 
void calc(int x,int f) {
    int fi=-1,se=-1;
    for(int i=F[x];i;i=nx[i]) if(nf[tt[i]]==x) {
        if(!t[tt[i]].empty()) {
            int tlen=*t[tt[i]].rbegin();
            se=max(se,tlen);
            if(se>fi) swap(fi,se); 
        } 
    }
    if(!clo[x]) se=max(se,0); if(se>fi) swap(se,fi); 
    if(!f&&g[x][0]!=-1&&g[x][1]!=-1) 
        mx.erase(mx.find(Node(g[x][0],g[x][1]))); 
    g[x][0]=fi; g[x][1]=se;
    if(fi!=-1&&se!=-1) mx.insert(Node(fi,se)); 
} 

void get_devide(int x,int fa) {
    if(fa) ADD(fa,x);
    nf[x]=fa;
    vis[x]=1;
    for(int i=fir[x];i;i=nxt[i]) if(!vis[to[i]]) {
        rt=0; nowsz=sz[to[i]];
        get_root(to[i],0); int tprt=rt;
        get_devide(rt,x);
        for(IT it=s[tprt].begin();it!=s[tprt].end();it++) {
            tpn=*it;
            int dis=get_lca(tpn.x,x);
            t[tprt].insert(dis); 
            s[x].insert(node(tpn.x,dis));
        }
    }
    s[x].insert(node(x,0));
    calc(x,1); 
} 

void open(int y,int x,int len) {
    s[y].insert(node(x,len));
    if(nf[y]) t[y].insert(get_lca(x,nf[y])); 
    if(len>g[y][0]||len>g[y][1]) calc(y,0);
    if(nf[y]) open(nf[y],x,get_lca(nf[y],x));
}

void close(int y,int x,int len) {
    s[y].erase(node(x,len));
    if(nf[y]) t[y].erase(t[y].find(get_lca(x,nf[y])));
    if(len==g[y][0]||len==g[y][1]) calc(y,0); 
    if(nf[y]) close(nf[y],x,get_lca(nf[y],x));
}

int totclose;
int main() {
#ifdef DEBUG
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
    memset(g,-1,sizeof(-1));
    read(n); nowsz=n;
    for(int i=1;i<n;i++) {
        int u,v;
        read(u); read(v);
        add(u,v);
    }
    dfs1(1,0);
    get_root(1,0); 
    get_devide(rt,0);
    read(Q); totclose=n;
    while(Q--) {
        scanf("%s",o);
        if(o[0]==C) {
            int x;
            read(x);
            if(clo[x]==1) {
                clo[x]=0;
                open(x,x,0);
                totclose++;
            }
            else {
                clo[x]=1;
                close(x,x,0);
                totclose--;
            }
        }
        else {
            if(totclose==1) puts("0");
            else if(totclose==0) puts("-1");
            else {
                Node tp=*mx.begin();
                int ans=tp.fi+tp.se;
                printf("%d\n",ans);    
            }
        } 
    }
    return 0;
}
/*
5
1 2
2 3
1 4
2 5
10
C 5
C 3
C 2
G
*/
View Code

 

以上是关于bzoj 1095: [ZJOI2007]Hide 捉迷藏的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1095: [ZJOI2007]Hide 捉迷藏

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

[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

bzoj 1095[ZJOI2007]Hide 捉迷藏

Bzoj1095 [ZJOI2007]Hide 捉迷藏

bzoj千题计划252:bzoj1095: [ZJOI2007]Hide 捉迷藏