[ZJOI2007] bzoj 1095 Hide 捉迷藏 - 动态点分治 - 学习笔记

64 篇文章 0 订阅
40 篇文章 0 订阅

动态点分治.屯板子


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#define N 100010
#define M N<<1
#define fir_sec(d,x,y) (x=d.top(),d.pop(),y=d.top(),d.push(x))
#define re_upd(x,y,t) (x.erase(y),x.push(t))
#define mp make_pair
#define inf -10000000
using namespace std;
typedef pair<int,int> pii;
struct edges{
    int to,pre;
}e[M];int h[N],etop,List[N],Lcnt,sz[N];
bool vis[N];int pre[N];
inline int add_edge(int u,int v)
{
    return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop;
}
struct node_heap{
    priority_queue<int> q;map<int,int> m;
    inline int push(int x) { q.push(x);return 0; }
    inline int erase(int x) { m[x]++;return 0; }
    inline int pop()
    {
        while(!q.empty()&&m[q.top()])
            m[q.top()]--,q.pop();
        if(!q.empty()) q.pop();return 0;
    }
    inline int top()
    {
        while(!q.empty()&&m[q.top()])
            m[q.top()]--,q.pop();
        return q.empty()?inf:q.top();
    }
}dh[N],ans;
int dv[N],ansv[N];
map<int,int> zid[N];//zid[x][y]=z
map<int,int> len[N];//len[x][z]=L
map<int,int> yv[N];//yv[x][y]=L
map<int,node_heap> yh[N];//yh[x][y]
int getsz(int x,int f)
{
    sz[x]=1;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!vis[y=e[i].to]&&e[i].to!=f) sz[x]+=getsz(y,x);
    return sz[List[++Lcnt]=x];
}
inline int getrt(int &x)
{
    for(int i=1,fsz=sz[x],t=fsz;i<=Lcnt;i++)
    {
        int ysz=fsz-sz[List[i]];
        for(int y=List[i],j=h[y];j;j=e[j].pre)
            if(sz[e[j].to]<sz[y]) ysz=max(ysz,sz[e[j].to]);
        if(ysz<t) x=List[i],t=ysz;
    }
    return Lcnt=0;
}
int solve(int x,int y,int z,int dis,int f)
{
    yh[y][z].push(len[x][z]=dis),zid[x][y]=z;
    for(int i=h[x],t;i;i=e[i].pre)
        if(!vis[t=e[i].to]&&e[i].to!=f) solve(t,y,z,dis+1,x);
    return 0;
}
int dfs(int x,int las)
{
    getsz(x,0),getrt(x),vis[x]=true,pre[x]=las;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!vis[y=e[i].to]) solve(y,x,y,0,0),
            dh[x].push((yv[x][y]=yh[x][y].top())+1);
    dh[x].push(0),dv[x]=dh[x].top();int x1,x2;
    fir_sec(dh[x],x1,x2),ans.push(ansv[x]=x1+x2);
    for(int i=h[x],y;i;i=e[i].pre)
        if(!vis[y=e[i].to]) dfs(y,x);
    return 0;
}
inline int update(int x)
{
    dh[x].push(0);int x1,x2;fir_sec(dh[x],x1,x2);
    if(x1+x2>ansv[x]) re_upd(ans,ansv[x],x1+x2),ansv[x]=x1+x2;
    for(int y=pre[x],z,l;y;y=pre[y])
    {
        z=zid[x][y],l=len[x][z],yh[y][z].push(l);
        if(yh[y][z].top()>yv[y][z])
        {
            re_upd(dh[y],yv[y][z]+1,yh[y][z].top()+1);
            yv[y][z]=yh[y][z].top(),fir_sec(dh[y],x1,x2);
            if(x1+x2>ansv[y]) re_upd(ans,ansv[y],x1+x2),ansv[y]=x1+x2;
        }
    }
    return 0;
}
inline int Oooops(int x)
{
    dh[x].erase(0);int x1,x2;fir_sec(dh[x],x1,x2);
    if(x1+x2<ansv[x]) re_upd(ans,ansv[x],x1+x2),ansv[x]=x1+x2;
    for(int y=pre[x],z,l;y;y=pre[y])
    {
        z=zid[x][y],l=len[x][z],yh[y][z].erase(l);
        if(yh[y][z].top()<yv[y][z])
        {
            re_upd(dh[y],yv[y][z]+1,yh[y][z].top()+1);
            yv[y][z]=yh[y][z].top(),fir_sec(dh[y],x1,x2);
            if(x1+x2<ansv[y]) re_upd(ans,ansv[y],x1+x2),ansv[y]=x1+x2;
        }
    }
    return 0;
}
bool iso[N];char opt[10];
#define gc getchar()
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int main()
{
    int n;scanf("%d",&n);
    for(int i=1,u,v;i<n;i++)
        u=inn(),v=inn(),add_edge(u,v),add_edge(v,u);
    dfs(1,0);int tot_cnt=n,m=inn();
    while(m--)
    {
        scanf("%s",opt);int x;
        if(opt[0]=='G')
            if(tot_cnt==1) printf("%d\n",0);
            else if(!tot_cnt) printf("%d\n",-1);
            else printf("%d\n",ans.top());
        else if(iso[x=inn()]) update(x),tot_cnt++,iso[x]=false;
        else Oooops(x),tot_cnt--,iso[x]=true;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值