bzoj1095 捉迷藏

我去,传说中的动态点分治入门题,想了我几个小时还是不知道怎么处理让不同子树对父亲节点产生贡献,我的方法无论怎么样都会被同一子树的信息影响,然后Orz了一波 PoPoQQQ,Hzwer大爷,对堆的处理很巧妙!具体的自己yy吧 (不过bzoj过了,spoj上Re了,不知道什么鬼)

/**************************************************************
    Problem: 1095
    User: Clare
    Language: C++
    Result: Accepted
    Time:7056 ms
    Memory:94404 kb
****************************************************************/
 
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
 
#define N 100010
#define INF 0x3f3f3f3f
 
int n,Sum,root,ans,total;
struct Edge{
    int to,next,value;
}edge[N*2],edge1[2000000];
int head[N],head1[N],tot,tot1;
int size[N],f[N],son[N];
bool done[N],White[N];
char S[5];
struct Heap{
    priority_queue<int> A,B;
    void Push(int k){A.push(k);}
    void Erase(int k){B.push(k);}
    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.size()?0:A.top();
    }
    int size(){return (int)A.size()-(int)B.size();}
    int S_top()
    {
        if(size()<2)return 0;
        int x=Top();Pop();
        int y=Top();Push(x);
        return y;
    }
}Ans,B[N],C[N];
 
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
 
void Addedge1(int u,int v,int w)
{
    tot1++;edge1[tot1].next=head1[u];edge1[tot1].to=v;edge1[tot1].value=w;head1[u]=tot1;
}
 
void Addedge(int u,int v,int w)
{
    tot++;edge[tot].next=head[u];edge[tot].to=v;edge[tot].value=w;head[u]=tot;
    tot++;edge[tot].next=head[v];edge[tot].to=u;edge[tot].value=w;head[v]=tot;
}
 
void Get_root(int k,int fa)
{
    size[k]=1;f[k]=0;
    for(int i=head[k];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa||done[v])
            continue;
        Get_root(v,k);
        size[k]+=size[v];
        f[k]=max(f[k],size[v]);
    }
    f[k]=max(f[k],Sum-f[k]);
    if(f[k]<f[root])
        root=k;
}
 
void DFS(int k,int fa,int rt,int d)
{
    Addedge1(k,rt,d);
    for(int i=head[k];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa||done[v])
            continue;
        DFS(v,k,rt,d+edge[i].value);
    }
}
 
void Rebuild(int k)
{
    done[k]=true;
    DFS(k,0,k,0);
    for(int i=head[k];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(done[v])
            continue;
        root=0;Sum=size[v];
        Get_root(v,root);
        Rebuild(root);
    }
}
 
void Turn_off(int k)
{
    for(int i=head1[k];i;i=edge1[i].next)
    {
        int pos=edge1[i].to;
        if(k==pos)
        {
            B[pos].Push(0);
            if(B[pos].size()==2)Ans.Push(B[pos].Top());
        }
        int ti=edge1[i].next;
        if(!ti)return;
        int Fa_pos=edge1[ti].to,tmp=C[pos].Top();
        C[pos].Push(edge1[ti].value);
        if(edge1[ti].value>tmp)
        {
            int Max=B[Fa_pos].Top()+B[Fa_pos].S_top(),Size=B[Fa_pos].size();
            if(tmp)
                B[Fa_pos].Erase(tmp);
            B[Fa_pos].Push(edge1[ti].value);
            int Now_max=B[Fa_pos].Top()+B[Fa_pos].S_top();
            if(Now_max>Max)
            {
                if(Size>=2)Ans.Erase(Max);
                if(B[Fa_pos].size()>=2)Ans.Push(Now_max);
            }
        }
    }
}
 
void Turn_on(int k)
{
    for(int i=head1[k];i;i=edge1[i].next)
    {
        int pos=edge1[i].to;
        if(pos==k)
        {
            if(B[pos].size()==2)Ans.Erase(B[pos].Top());
            B[pos].Erase(0);
        }
        int ti=edge1[i].next;
        if(!ti)return;
        int Fa_pos=edge1[ti].to,tmp=C[pos].Top();
        C[pos].Erase(edge1[ti].value);
        if(edge1[ti].value==tmp)
        {
            int Max=B[Fa_pos].Top()+B[Fa_pos].S_top(),Size=B[Fa_pos].size();
            B[Fa_pos].Erase(tmp);
            if(C[pos].Top())
                B[Fa_pos].Push(C[pos].Top());
            int Now_max=B[Fa_pos].Top()+B[Fa_pos].S_top();
            if(Now_max<Max)
            {
                if(Size>=2)Ans.Erase(Max);
                if(B[Fa_pos].size()>=2)Ans.Push(Now_max);
            }
        }
    }
}
 
int main()
{
    n=read();
    for(int i=1;i<=n-1;i++)
    {
        White[i]=true;
        int x=read(),y=read();
        Addedge(x,y,1);
    }
    White[n]=true;
    Sum=n;f[0]=INF;root=0;
    Get_root(1,root);
    Rebuild(root);
    for(int i=1;i<=n;i++)
        C[i].Push(0);
    for(int i=1;i<=n;i++)
    {
        total++;Turn_off(i);
    }
    int Q=read();
    while(Q--)
    {
        scanf("%s",S);
        if(S[0]=='G')
        {
            if(total==0)
                printf("%d\n",-1);
            else if(total==1)
                printf("%d\n",0);
            else printf("%d\n",Ans.Top());
        }
        else
        {
            int x=read();
            White[x]^=1;
            if(!White[x])Turn_on(x),total--;
            else Turn_off(x),total++;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值