BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)

1095: [ZJOI2007]Hide 捉迷藏

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 5415  Solved: 2276
[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。

思路:
把每次分治的重心连成一棵树,树的深度是logn,
每次修改一个结点只影响它到树根的一条链
这题具体实现的时候要维护三层堆
C.每个重心存所有子树到其距离
B.每个重心存各个子树最大值,即子结点堆C的最大值
A.全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
vector<int>G[maxn];
int dep[maxn],lg[maxn],f[maxn][22];
int root,now_size,son[maxn];
int vis[maxn],father[maxn],have[maxn];
struct node//手搓一个可以删除任意元素的优先队列。
{
    priority_queue<int>q,del;
    void Push(int x){q.push(x);}
    void Erase(int x){del.push(x);}
    int Top()
    {
        while(del.size()&&del.top()==q.top()) del.pop(),q.pop();
        return q.top();
    }
    void Pop()
    {
        while(del.size()&&del.top()==q.top()) del.pop(),q.pop();
        q.pop();
    }
    int Sectop()
    {
        int tmp1=Top();Pop();int tmp2=Top();
        Push(tmp1); return tmp2;
    }
    int Size() {return q.size()-del.size();}
}c[maxn],d[maxn],ans;
void ADD(node &e)
{
    if(e.Size()>1) ans.Push(e.Top()+e.Sectop());
}
void Delete(node &e)
{
    if(e.Size()>1) ans.Erase(e.Top()+e.Sectop());
}
void get_dep(int v,int fa)
{
    dep[v]=dep[fa]+1;
    f[v][0]=fa;
    for(int i=1;(1<<i)<=dep[v];i++)
        f[v][i]=f[f[v][i-1]][i-1];
    for(int i=0;i<G[v].size();i++)
        if(G[v][i]!=fa) get_dep(G[v][i],v);
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    while(dep[x]>dep[y])
    {
        int h=lg[dep[x]-dep[y]];
        x=f[x][h];
    }
    if(x==y) return x;
    for(int i=lg[dep[x]];i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}
void get_root(int v,int fa,int SIZE)
{
    son[v]=1;
    int ma=0;
    for(int i=0;i<G[v].size();i++)
    {
        int to=G[v][i];
        if(to==fa||vis[to]) continue;
        get_root(to,v,SIZE);
        son[v]+=son[to];
        ma=max(ma,son[to]);
    }
    ma=max(ma,SIZE-son[v]);
    if(ma<now_size)
    {
        now_size=ma;
        root=v;
    }
}
void work(int v,int fa,int rt)
{
    d[root].Push(dep[v]+dep[rt]-2*dep[LCA(v,rt)]);
    for(int i=0;i<G[v].size();i++)
    {
        int to=G[v][i];
        if(to==fa||vis[to]) continue;
        work(to,v,rt);
    }
}
void build(int v,int fa)
{
    vis[v]=1;
    father[v]=fa;
    c[v].Push(0);
    work(v,fa,fa);
    for(int i=0;i<G[v].size();i++)
    {
        int to=G[v][i];
        if(to==fa||vis[to]) continue;
        get_root(root=to,v,now_size=son[to]);
        int tmp=root;
        build(root,v);
        c[v].Push(d[tmp].Top());
    }
    ADD(c[v]);
}
void turn_on(int x)
{
    Delete(c[x]);
    c[x].Erase(0);
    ADD(c[x]);
    for(int i=x;i;i=father[i])
    {
        int fa=father[i];
        Delete(c[fa]);
        if(d[i].Size()) c[fa].Erase(d[i].Top());
        d[i].Erase(dep[x]+dep[fa]-2*dep[LCA(x,fa)]);
        if(d[i].Size()) c[fa].Push(d[i].Top());
        ADD(c[fa]);
    }
}
void turn_off(int x)
{
    Delete(c[x]);
    c[x].Push(0);
    ADD(c[x]);
    for(int i=x;i;i=father[i])
    {
        int fa=father[i];
        Delete(c[fa]);
        if(d[i].Size()) c[fa].Erase(d[i].Top());
        d[i].Push(dep[x]+dep[fa]-2*dep[LCA(x,fa)]);
        c[fa].Push(d[i].Top());
        ADD(c[fa]);
    }
}
int main()
{
    for(int i=2;i<maxn;i++) lg[i]=lg[i/2]+1;
    int n;scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    get_dep(1,0);
    get_root(root=1,0,now_size=n);
    build(root,0);
    int num=0;
    int Q;scanf("%d",&Q);
    while(Q--)
    {
        char t[2];int x;scanf("%s",&t);
        if(t[0]=='C')
        {
            scanf("%d",&x);
            if(!have[x]) turn_on(x),have[x]=1,num++;
            else turn_off(x),have[x]=0,num--;
        }
        else
        {
            if(num==n-1) printf("0\n");
            else if(num==n) printf("-1\n");
            else printf("%d\n",ans.Top());
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/albertluf/article/details/81567005