bzoj:1095: [ZJOI2007]Hide 捉迷藏

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

 

写的时候感觉脑子要炸了……代码会很丑……

是正常三层堆的做法。

 

#include<queue>
#include<cstdio>
#include<algorithm>
#define MN 100001
using namespace std;
int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<'0'||read_ca>'9') read_ca=getchar();
    while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
struct na{
    int x,y,z,ne;
}b[2*MN],bb[1700001],bv[MN];
int n,m,ma,la[MN],num=0,fa[MN],s[MN],lla[MN],vla[MN],size,root,nnum=0,vnum=0,mmh,ha[MN],ppp=0,nm=0;
bool v[MN],p[MN];
struct nma{
    int x,fr;
    bool operator < (nma a)const{return x<a.x;}
};
nma m_a(int x,int fr){nma a;a.x=x;a.fr=fr;return a;}
const int INF=1e9;
priority_queue <nma> q[MN],qv[MN],all;
inline void in(int x,int y){b[++num].y=y;b[num].ne=la[x];la[x]=num;}
inline void add(int u,int x,int y,int z){bb[++nnum].x=x;bb[nnum].y=y;bb[nnum].z=z;bb[nnum].ne=lla[u];lla[u]=nnum;}
inline void newin(int x,int y){bv[++vnum].y=y;bv[vnum].ne=vla[x];vla[x]=vnum;}
inline void gs(int x,int f){
    int u=0;s[x]=1;
    for (int i=la[x];i;i=b[i].ne)
    if (!v[b[i].y]&&b[i].y!=f) gs(b[i].y,x),s[x]+=s[b[i].y],u=u>s[b[i].y]?u:s[b[i].y];
    if (u<size-s[x]) u=size-s[x];
    if (u<ma) root=x,ma=u;
}
inline void ch(int x){
    for (int i=vla[x];i;i=bv[i].ne) if (!q[bv[i].y].empty())qv[x].push(m_a(q[bv[i].y].top().x,bv[i].y));
}
inline void cg(int x){
    while(!qv[x].empty()){if (!q[qv[x].top().fr].empty()) if (qv[x].top().x==q[qv[x].top().fr].top().x) break;qv[x].pop();}
    if (qv[x].empty()){ha[x]=-1;return;}
    nma mmh=qv[x].top();int u=mmh.x;
    qv[x].pop();
    while(!qv[x].empty()){if (qv[x].top().fr!=mmh.fr)if (!q[qv[x].top().fr].empty()) if (qv[x].top().x==q[qv[x].top().fr].top().x) break;qv[x].pop();}
    if (qv[x].empty()){if (!p[x]) {ha[x]=-1;qv[x].push(mmh);return;}}else u+=qv[x].top().x;
    qv[x].push(mmh);
    ha[x]=u;
    all.push(m_a(u,x));
    while(!all.empty()){if (all.top().x==ha[all.top().fr]) break;all.pop();}
}
inline void gx(int x,int y){
    mmh=q[x].top().x;
    while(!q[x].empty()){if (p[q[x].top().fr]) break;q[x].pop();}
    if (!q[x].empty()) if (q[x].top().x!=mmh) qv[y].push(m_a(q[x].top().x,x));
    while(!qv[y].empty()){if (!q[qv[y].top().fr].empty()) if (qv[y].top().x==q[qv[y].top().fr].top().x) break;qv[y].pop();}
}
inline void dfs(int x,int f,int dis){
    if (dis==1) mmh=++nm,newin(root,nm);
    if (f) add(x,mmh,root,dis),q[mmh].push(m_a(dis,x));
    for (int i=la[x];i;i=b[i].ne)
    if (b[i].y!=f&&(!v[b[i].y])) dfs(b[i].y,x,dis+1);
}
inline void work(int x,int siz,int f){
    size=siz;ma=INF;gs(x,0);x=root;
    dfs(x,0,0);ha[x]=-1;ch(x);cg(x);v[x]=1;
    for (int i=la[x];i;i=b[i].ne)
    if (!v[b[i].y]) work(b[i].y,s[b[i].y],x);
}
inline int min(int x,int y){return x>y?y:x;}
char cc[10];
int main(){
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    int x,y;register int j;
    ppp=n=read();
    for (int i=1;i<n;i++) x=read(),y=read(),in(x,y),in(y,x);
    for (int i=1;i<=n;i++) p[i]=1;
    work(1,n,0);
    n=read();
    while(n--){
        scanf("%s",cc);
        if (cc[0]=='C'){
            if (p[y=read()]^=1)
            for (j=lla[y];j;j=bb[j].ne){
                if (q[bb[j].x].empty()) mmh=-1;else mmh=q[bb[j].x].top().x;
                q[bb[j].x].push(m_a(bb[j].z,y));
                while(!q[x].empty()){if (p[q[x].top().fr]) break;q[x].pop();}
                if (q[bb[j].x].top().x!=mmh) qv[bb[j].y].push(m_a(q[bb[j].x].top().x,bb[j].x)),cg(bb[j].y);
            }else for (j=lla[y];j;j=bb[j].ne) gx(bb[j].x,bb[j].y),cg(bb[j].y);cg(y);
            if (p[y]) ppp++;else ppp--;
        }
        else if (!ppp)printf("-1\n");else if (ppp==1) printf("0\n");else{
            while(!all.empty()){if (all.top().x==ha[all.top().fr]) break;all.pop();}
            printf("%d\n",all.top().x);
        }
    }
}
View Code

 

转载于:https://www.cnblogs.com/Enceladus/p/5414591.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值