• 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

    HINT

    对于100%的数据, N ≤100000, M ≤500000。

    Source

    今天重构代码终于把这个无比操蛋的动态点分治给做掉了...

    每个点四个堆+一个全局堆+一个全局删除堆(一共6个堆!!!)的这种鬼题目我也是不想说什么...

    大体思想是这样的:

    考虑到一条路径必然是经过一个点的

    我们考虑点分治的基本思想,考虑经过这一个点的所有路径的最大路径

    那么经过这个点的路径必然由这个点的两条位于不同子树中的路径组合而成

    如果还要最大的话,那么一定是最大的一条路径加上次大的路径

    于是我们就萌发了一个冲动:每个节点都用堆来维护这些东西

    于是每个节点需要两个堆:

    A堆存该点子树中到该点上层重心的路径大小

    B堆存该点每个子树中的A堆的top();

    考虑到我们查询不可能在一次访问所有点,那么我们还需要一个全局堆:存每个节点B堆的first和second;实现直接查询

    然后好像就做出来了的样子,然而待修改真的会让人感到特判的绝望,貌似我在WG数据下还是WA了一个点

    修改的话,我们参考网络的套路,建立对于A,B,C三个堆都建立一个对应的删除堆,就可以方便我们愉快的删除了(MDZZ我竟然忘记了网络的套路...还想打可并堆删除...)

    大体操作就是插入堆和删除堆一起pop()直到二者不同位置

    那么我们修改的时候,首先肯定是修改当前重心的log个上层重心:

    对于每个重心,先把他的B堆在全局堆中的贡献删掉(放入删除堆),然后把他下层重心A堆的对于他B堆的贡献删掉(放入删除堆),

    然后用修改点去更新下层重心的B堆,然后拿下层重心的B堆在去更新全局堆(手动模拟一下删除堆的作用就懂了,加入堆在删除是无需pop())

    于是update貌似就这样打完了,真的不容易啊

    附上代码:

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<set>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<ctime>
    #define lson num<<1
    #define rson num<<1|1
    using namespace std;
    typedef long long ll;
    const int N=500050;
    const int Inf=2147483647;
    int gi()
    {
        int x=0,flag=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*flag;
    }
    int head[N],to[N],nxt[N],c[N];
    int size[N],f[N],dis[N],FA[N],vis[N],deep[N];
    int son[N],s[N],top[N],F[N];
    int SIZE,root,cnt;
    struct heap{
        priority_queue<int>a,b;
        void add(int x){a.push(x);}
        void del(int x){b.push(x);}
        int first(){
    	while((!a.empty()&&!b.empty())&&(a.top()==b.top())) a.pop(),b.pop();
    	return a.top();
        }
        int second(){
    	int x=first();
    	a.pop();int y=first();a.push(x);
    	return y;
        }
        int size() {return a.size()-b.size();}
    }A[N],B[N],C;
    void Add(int x){if(B[x].size()>=2) C.add(B[x].first()+B[x].second());}
    void Del(int x){if(B[x].size()>=2) C.del(B[x].first()+B[x].second());}
    void dfs1(int x,int fa){
        deep[x]=deep[fa]+1;s[x]=1;
        for(int i=head[x];i;i=nxt[i]){
    	int y=to[i];
    	if(y!=fa){
    	    dfs1(y,x);F[y]=x;s[x]+=s[y];
    	    if(s[y]>s[son[x]]) son[x]=y;
    	}
        }
    }
    void dfs2(int x,int fa){
        top[x]=fa;
        if(son[x]) dfs2(son[x],fa);
        for(int i=head[x];i;i=nxt[i]){
    	int y=to[i];
    	if(y!=F[x]&&y!=son[x]) dfs2(y,y);
        }
    }
    int LCA(int u,int v){
        int x=u,y=v;
        while(top[x]!=top[y]){
    	if(deep[top[x]]<deep[top[y]]) swap(x,y);
    	x=F[top[x]];
        }
        if(deep[x]<deep[y]) swap(x,y);
        return deep[u]+deep[v]-2*deep[y];
    }
    void getroot(int x,int fa){
        size[x]=1;f[x]=0;
        for(int i=head[x];i;i=nxt[i]){
    	int y=to[i];
    	if(y!=fa&&!vis[y]){
    	    getroot(y,x);
    	    size[x]+=size[y];
    	    f[x]=max(f[x],size[y]);
    	}
        }
        f[x]=max(f[x],SIZE-size[x]);
        if(f[x]<f[root]) root=x;
    }
    void getdeep(int x,int fa){
        A[root].add(dis[x]);
        for(int i=head[x];i;i=nxt[i]){
    	int y=to[i];
    	if(!vis[y]&&y!=fa){
    	    dis[y]=dis[x]+1;
    	    getdeep(y,x);
    	}
        }
    }
    void work(int x){
        vis[x]=1;B[x].add(0);
        for(int i=head[x];i;i=nxt[i]){
    	int y=to[i];
    	if(!vis[y]){
    	    dis[y]=1;SIZE=size[y];root=0;getroot(y,0);getdeep(y,0);
    	    FA[root]=x;B[x].add(A[root].first());
    	    work(root);
    	}
        }
        Add(x);
    }
    void lnk(int x,int y){
        to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
        to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
    }
    void update(int x){
        Del(x);c[x]^=1;
        if(!c[x]) B[x].add(0);
        else B[x].del(0);
        Add(x);
        for(int i=x;FA[i];i=FA[i]){
    	int y=FA[i];
    	Del(y);
    	if(A[i].size()) B[y].del(A[i].first());
    	if(!c[x]) A[i].add(LCA(x,y));
    	else A[i].del(LCA(x,y));
    	if(A[i].size()) B[y].add(A[i].first());
    	Add(y);
        }
    }
    int main()
    {
        //freopen("2.in","r",stdin);
        //freopen("2.out","w",stdout);
        int n=gi(),x,y;
        for(int i=1;i<n;i++){
    	x=gi(),y=gi();lnk(x,y);
        }
        dfs1(1,0);dfs2(1,1);
        root=0;f[0]=Inf;SIZE=n;
        getroot(1,0);work(root);
        int m=gi();
        char ch[3];
        for(int i=1;i<=m;i++){
    	scanf("%s",ch+1);
    	if(ch[1]=='C') x=gi(),update(x);
    	else{
    	printf("%d
    ",C.first());
           }
        }
    }
    
  • 相关阅读:
    如何实现文字两端对齐?
    三目运算符的复杂运算(条件嵌套判断)
    微信小程序实现图片上传,预览,删除
    微信小程序滚动条返回顶部
    vue+axios下载文件的实现
    java script 运算符
    关于placeholder提示内容出现在textarea底部问题
    js基础知识
    java script 字符串
    java script 函数
  • 原文地址:https://www.cnblogs.com/qt666/p/6596941.html
Copyright © 2020-2023  润新知