BZOJ1095: [ZJOI2007]Hide 捉迷藏

所以为什么这道是动态点分治的模板题….细节好爆炸

动态点分治按每次分治的重心建树,然后在分治的过程中处理出每个点在原树中到它新树中log个父亲的距离,它在新树中的层数
然后维护(好多个)堆,分别是(新树中)每个点的子树内所有点到它父亲的距离heap[x],(新树中)每个点各个子树到它的最长链heap2[x](注意自己到自己的一条长度为0的链以处理子树延伸上来的单链),还有一个全局的堆维护每个重心处的答案(他的子树内经过他的最长链,即取出最长的两条不同子树到它的最长链)

code:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;

inline void up(int &x,const int &y){if(xinline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 101000;
const int maxd = 20;

int n,m;
struct edge
{
    int y,nex;
    edge(){}
    edge(const int _y,const int _nex){y=_y;nex=_nex;}
}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=edge(y,fir[x]);fir[x]=len;}

bool light[maxn]; int countl;
struct node
{
    int x,i,ti;
    node(){}
    node(const int _x,const int _i,const int _ti){x=_x;i=_i;ti=_ti;}
};
inline bool operator <(node x,node y){return x.xheap[maxn],heap2[maxn],Ans;
//                  到fa距离   son到x距离max
int th2[maxn];

int ans[maxn];

int fa[maxn],dis[maxn][maxd];
int siz[maxn];
int dep[maxn];
void find_root(const int x,const int ff,const int num,const int lasdep,int &root)
{
    int maxs=0;
    siz[x]=1;
    for(int k=fir[x];k;k=a[k].nex)
    {
        const int y=a[k].y;
        if(!dep[y]&&y!=ff)
        {
            dis[y][lasdep]=dis[x][lasdep]+1;
            find_root(y,x,num,lasdep,root);
            up(maxs,siz[y]);
            siz[x]+=siz[y];
        }
    }
    if(maxs*2<=num&&(num-siz[x])*2<=num) root=x;
}
void upd(const int x,const int ff,const int root)
{
    heap[root].push(node(dis[x][dep[root]-1],x,0));
    for(int k=fir[x];k;k=a[k].nex)
    {
        const int y=a[k].y;
        if(y!=ff&&!dep[y]) upd(y,x,root);
    }
}
void Divide(int x,const int ff,const int num,int nowdep)
{
    int root=x;
    if(num!=1) find_root(x,ff,num,nowdep-1,root);
    x=root;
    dep[x]=nowdep; fa[x]=ff;
    upd(x,ff,root);

    node t1=heap[x].top();
    heap2[ff].push(node(t1.x,x,0));

    heap2[x].push(node(0,x,0));
    for(int k=fir[x];k;k=a[k].nex)
    {
        const int y=a[k].y;
        if(!dep[y]&&y!=ff)
        {
            int ny=siz[x]>siz[y]?siz[y]:num-siz[x];
            dis[y][nowdep]=1;
            Divide(y,x,ny,nowdep+1);
        }
    }

    if(num==1) return;

    t1=heap2[x].top();
    heap2[x].pop();
    node t2=heap2[x].top();
    Ans.push(node(t1.x+t2.x,x,0));
    ans[x]=t1.x+t2.x;
    heap2[x].push(t1);
    return;
}
node get_top1(const int x)
{
    node tmp; bool flag=false;
    while(!heap[x].empty())
    {
        tmp=heap[x].top();
        if(!light[tmp.i]) { flag=true; break; }
        heap[x].pop();
    }
    if(!flag) tmp.i=-1;
    return tmp;
}
node get_top2(const int x)
{
    node tmp,t1; bool flag=false;
    while(!heap2[x].empty())
    {
        tmp=heap2[x].top(); heap2[x].pop();
        if(tmp.ti!=th2[tmp.i]) continue;
        flag=true; break;
    }
    if(!flag) tmp.i=-1;
    return tmp;
}
void On(const int x) /
{
    light[x]=true; countl--;
    th2[x]++;

    node t1,t2;
    t1=get_top1(x);
    if(t1.i!=-1&&fa[x]) heap2[fa[x]].push(node(t1.x,x,th2[x]));
    for(int i=fa[x];i;i=fa[i])
    {
        th2[i]++;
        if(!light[i]) heap2[i].push(node(0,i,th2[i]));

        t1=get_top2(i);
        t2=get_top2(i);
        if(t1.i!=-1) heap2[i].push(t1);
        if(t2.i!=-1) heap2[i].push(t2);

        if(t2.i==-1) ans[i]=0;
        else if(t1.x+t2.x!=ans[i])
            ans[i]=t1.x+t2.x,Ans.push(node(ans[i],i,0));

        t1=get_top1(i);
        if(t1.i!=-1&&fa[i]) heap2[fa[i]].push(node(t1.x,i,th2[i]));
    }
}
void Off(const int x) /
{
    light[x]=false; countl++;
    th2[x]++;

    node t1,t2;
    heap[x].push(node(dis[x][dep[x]-1],x,0));
    heap2[x].push(node(0,x,th2[x]));
    t1=get_top2(x),t2=get_top2(x);
    if(t1.i!=-1) heap2[x].push(t1);
    if(t2.i!=-1) heap2[x].push(t2);
    if(t2.i!=-1&&t1.x+t2.x!=ans[x])
        ans[x]=t1.x+t2.x,Ans.push(node(t1.x+t2.x,x,0));

    for(int la=x,i=fa[x];i;la=i,i=fa[i])
    {
        th2[i]++;
        if(!light[i]) heap2[i].push(node(0,i,th2[i]));

        t1=get_top1(la); heap2[i].push(node(t1.x,la,th2[la])); //

        t1=get_top2(i),t2=get_top2(i);
        if(t1.i!=-1) heap2[i].push(t1);
        if(t2.i!=-1) heap2[i].push(t2);

        if(t2.i!=-1&&t1.x+t2.x!=ans[i]) 
            ans[i]=t1.x+t2.x,Ans.push(node(t1.x+t2.x,i,0));
        heap[i].push(node(dis[x][dep[i]-1],x,0));
    }
}

int main()
{
    //light false
    read(n); countl=n;
    for(int i=1;iint x,y; read(x); read(y);
        ins(x,y); ins(y,x);
    }
    Divide(1,0,n,1);

    char str[10]; read(m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",str);
        if(str[0]=='C')
        {
            int x; read(x);
            if(light[x]) Off(x);
            else On(x);
        }
        else
        {
            if(!countl) { printf("-1\n");continue; }
            if(countl==1) { printf("0\n");continue; }
            
            while(1)
            {
                node tmp=Ans.top();
                if(ans[tmp.i]!=tmp.x) Ans.pop();
                else { printf("%d\n",tmp.x); break; }
            }
        }
    }

    return 0;
}


你可能感兴趣的:(BZOJ,动态点分治,堆)