P2056 [ZJOI2007]捉迷藏(边分治、点分治)

题目链接
这题原来一直T,题解也大多是点分治括号序列等。
我是用边分治写的。
加上快读和O2,这题就过了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define llu unsigned ll
using namespace std;


char buffer[100001],*S,*T;
inline char Get_Char()
{
    if (S==T)
    {
        T=(S=buffer)+fread(buffer,1,100001,stdin);
        if (S==T) return EOF;
    }
    return *S++;
}
inline int read()
{
    char c;int re=0;
    for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
    while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
    return re;
}

inline char read_charA()
{
    char c;
    for(c=Get_Char();c<'A'||c>'Z';c=Get_Char());
    return c;
}

const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=200100;
int head[maxn],ver[maxn*20],edge[maxn*20],nt[maxn*20];
int Head[maxn],Ver[maxn<<1],Edge[maxn<<1],Nt[maxn<<1],tail[maxn],pre[maxn*20];
int d[maxn];
bool ha[maxn];

int nown,n,tot,TOT,root,midedge,maxx,cnt;

void init(void)
{
    memset(head,0,sizeof(head));
    tot=1;
}

void Init(void)
{
    memset(Head,0,sizeof(Head));
    TOT=1;
}

void add(int x,int y,int z)
{
    ver[++tot]=y,edge[tot]=z;
    nt[tot]=head[x],head[x]=tot;
}

void Add(int x,int y,int z)
{
    Ver[++TOT]=y,Edge[TOT]=z;
    Nt[TOT]=Head[x],Head[x]=TOT;
}

void get_pre(void)
{
    memset(tail,0,sizeof(tail));
    for(int x=1;x<=nown;x++)
    {
        for(int i=Head[x];i;i=Nt[i])
        {
            pre[i]=tail[x];
            tail[x]=i;
        }
    }
}

void del(int x,int i)
{
    if(Head[x]==i) Head[x]=Nt[i];
    else Nt[pre[i]]=Nt[i];

    if(tail[x]==i) tail[x]=pre[i];
    else pre[Nt[i]]=pre[i];
}


void build(int x,int fa)
{
    int now=0;
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i],z=edge[i];
        if(y==fa) continue;

        if(!now)
        {
            Add(x,y,z),Add(y,x,z);
            now=x;
        }
        else
        {
            ha[++nown]=false;
            Add(nown,now,0),Add(now,nown,0);
            Add(y,nown,z),Add(nown,y,z);
            now=nown;
        }
        build(y,x);
    }
}


void rebuild(void)
{
    Init();
    nown=n;

    for(int i=1;i<=nown;i++) ha[i]=1;

    build(1,0);
    get_pre();

    init();

}


struct point
{
    int y;
    int dis;
    point(){}
    point(int a,int b)
    {
        y=a,dis=b;
    }
    friend bool operator <(const point &a,const point &b)
    {
        return a.dis<b.dis;
    }
};

struct node
{
    int root,midlen,ans;
    int lson,rson;
    priority_queue<point>q;
}t[maxn<<1];

void _init(void)
{
    for(int i=1;i<maxn<<2;i++)
    {
        while(t[i].q.size())
            t[i].q.pop();
        t[i].lson=t[i].rson=0;
    }
    cnt=1;
}

void dfs_size(int x,int fa,int dis)
{
    add(x,root,dis);
    if(ha[x]) t[root].q.push(point(x,dis));
    d[x]=1;

    for(int i=Head[x];i;i=Nt[i])
    {
        int y=Ver[i],z=Edge[i];
        if(y==fa) continue;

        dfs_size(y,x,dis+z);

        d[x]+=d[y];
    }
}


void dfs_midedge(int x,int nowi)
{
    if(max(d[x],d[t[root].root]-d[x])<maxx)
    {
        maxx=max(d[x],d[t[root].root]-d[x]);
        midedge=nowi;
    }

    for(int i=Head[x];i;i=Nt[i])
    {
        int y=Ver[i];
        if(i!=(nowi^1)) dfs_midedge(y,i);
    }
}

void pushup(int id)
{
    t[id].ans=-1;
    while(t[id].q.size()&&ha[t[id].q.top().y]==0) t[id].q.pop();

    int lson=t[id].lson,rson=t[id].rson;

    if(lson==0&&rson==0)
    {
        if(ha[t[id].root]) t[id].ans=0;
    }
    else
    {
        if(t[lson].ans>t[id].ans) t[id].ans=t[lson].ans;
        if(t[rson].ans>t[id].ans) t[id].ans=t[rson].ans;
        if(t[lson].q.size()&&t[rson].q.size())
            t[id].ans=max(t[id].ans,t[lson].q.top().dis+t[rson].q.top().dis+t[id].midlen);
    }
}

void dfs(int id,int x)
{
    root=id,maxx=nown,midedge=0;
    t[id].root=x;

    dfs_size(x,0,0);
    dfs_midedge(x,0);

    if(midedge)
    {
        int p1=Ver[midedge];
        int p2=Ver[midedge^1];

        t[id].midlen=Edge[midedge];

        t[id].lson=++cnt;
        t[id].rson=++cnt;

        del(p1,midedge^1);
        del(p2,midedge);

        dfs(t[id].lson,p1);
        dfs(t[id].rson,p2);

    }
    pushup(id);
}

void update(int x)
{
    ha[x]^=1;
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i],z=edge[i];
        if(ha[x]==1) t[y].q.push(point(x,z));
        pushup(y);
    }
}

int main(void)
{
    n=read();
    init();
    cnt=1;
    int x,y;
    for(int i=1;i<n;i++)
    {
        x=read(),y=read();
        add(x,y,1);
        add(y,x,1);
    }

    rebuild();
    dfs(1,1);
    int m,pos;
    char str;
    m=read();
    for(int i=1;i<=m;i++)
    {
        str=read_charA();
        if(str=='G')
        {
            if(t[1].ans==-1) printf("They have disappeared.\n");
            else printf("%d\n",t[1].ans);
        }
        else
        {
            pos=read();
            update(pos);
        }
    }
    return 0;
}

2020/9/24更新:

考虑本题的点分治做法。

对于点分树上的每个以 x x x 为根的子树 ,我们记录 m a x ( x ) max(x) max(x) 为点分树上以 x x x 为根的子树中的节点,到点分树上 x x x 的父亲 f a ( x ) fa(x) fa(x) 在原树上的最大距离。

对于点分树上的每一点 x x x,我们记录其 m a x ( s o n ( x ) ) max(son(x)) max(son(x)) 的最大值和次大值。此时全局最大的每个点的 m a x ( s o n ( x ) ) max(son(x)) max(son(x)) 的最大值加次大值即为答案。注意:若当前点 x x x 为黑点,那么我们需要再记录一个 0 0 0 ,表示到当前点也可以。

考虑修改,我们可以每个节点开两个大顶堆维护,以当前节点为根的子树中的节点到父亲节点的最大值,儿子节点的 m a x max max。删除的时候利用懒惰删除大法,只标记不删除。

然后开一个全局的大顶堆维护答案即可。

时间复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
namespace onlyzhao
{
    #define ui unsigned int
    #define ll long long
    #define llu unsigned ll
    #define ld long double
    #define pr make_pair
    #define pb push_back
    #define lc (cnt<<1)
    #define rc (cnt<<1|1)
    #define len(x)  (t[(x)].r-t[(x)].l+1)
    #define tmid ((l+r)>>1)
    #define fhead(x) for(int i=head[(x)];i;i=nt[i])
    //#define max(x,y) ((x)>(y)?(x):(y))
    //#define min(x,y) ((x)>(y)?(y):(x))
    #define one(n) for(int i=1;i<=(n);i++)
    #define rone(n) for(int i=(n);i>=1;i--)
    #define fone(i,x,n) for(int i=(x);i<=(n);i++)
    #define frone(i,n,x) for(int i=(n);i>=(x);i--)
    #define fonk(i,x,n,k) for(int i=(x);i<=(n);i+=(k))
    #define fronk(i,n,x,k) for(int i=(n);i>=(x);i-=(k))
    #define two(n,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define ftwo(i,n,j,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define fvc(vc) for(int i=0;i<vc.size();i++)
    #define frvc(vc) for(int i=vc.size()-1;i>=0;i--)
    #define forvc(i,vc) for(int i=0;i<vc.size();i++)
    #define forrvc(i,vc) for(int i=vc.size()-1;i>=0;i--)
    #define cls(a) memset(a,0,sizeof(a))
    #define cls1(a) memset(a,-1,sizeof(a))
    #define clsmax(a) memset(a,0x3f,sizeof(a))
    #define clsmin(a) memset(a,0x80,sizeof(a))
    #define cln(a,num) memset(a,0,sizeof(a[0])*num)
    #define cln1(a,num) memset(a,-1,sizeof(a[0])*num)
    #define clnmax(a,num) memset(a,0x3f,sizeof(a[0])*num)
    #define clnmin(a,num) memset(a,0x80,sizeof(a[0])*num)
    #define sc(x) scanf("%d",&x)
    #define sc2(x,y) scanf("%d%d",&x,&y)
    #define sc3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define scl(x) scanf("%lld",&x)
    #define scl2(x,y) scanf("%lld%lld",&x,&y)
    #define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
    #define scf(x) scanf("%lf",&x)
    #define scf2(x,y) scanf("%lf%lf",&x,&y)
    #define scf3(x,y,z) scanf("%lf%lf%lf",&x,&y,&z)
    #define scs(x) scanf("%s",x+1)
    #define scs0(x) scanf("%s",x)
    #define scline(x) scanf("%[^\n]%*c",x+1)
    #define scline0(x) scanf("%[^\n]%*c",x)
    #define pcc(x) putchar(x)
    #define pc(x) printf("%d\n",x)
    #define pc2(x,y) printf("%d %d\n",x,y)
    #define pc3(x,y,z) printf("%d %d %d\n",x,y,z)
    #define pck(x) printf("%d ",x)
    #define pcl(x) printf("%lld\n",x)
    #define pcl2(x,y) printf("%lld %lld\n",x,y)
    #define pcl3(x,y,z) printf("%lld %lld %d\n",x,y,z)
    #define pclk(x) printf("%lld ",x)
    #define pcf2(x) printf("%.2f\n",x)
    #define pcf6(x) printf("%.6f\n",x)
    #define pcf8(x) printf("%.8f\n",x)
    #define pcs(x) printf("%s\n",x+1)
    #define pcs0(x) printf("%s\n",x)
    #define pcline(x) printf("%d**********\n",x)
    #define casett int tt;sc(tt);int pp=0;while(tt--)

    char buffer[100001],*S,*T;
    inline char Get_Char()
    {
        if (S==T)
        {
            T=(S=buffer)+fread(buffer,1,100001,stdin);
            if (S==T) return EOF;
        }
        return *S++;
    }
    inline int read()
    {
        char c;int re=0;
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
        while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
        return re;
    }
};
using namespace onlyzhao;
using namespace std;

const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=998244353;
const int p=mod;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=100100;
const int maxm=1000100;
const int maxp=100100;
const int up=100100;
const int g=3;

int head[maxn],ver[maxn<<1],nt[maxn<<1],tot=1;

void add(int x,int y)
{
    ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}

int d[maxn],id[maxn],rk[maxn<<1],dd[maxn<<1];
int f[maxn<<1][20],_log[maxn<<1];
int tcnt=0,n;

void dfs(int x,int fa)
{
    id[x]=++tcnt;rk[tcnt]=x;dd[tcnt]=d[x];
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa) continue;
        d[y]=d[x]+1;
        dfs(y,x);
        rk[++tcnt]=x,dd[tcnt]=d[x];
    }
}

void ST(void)
{
    _log[0]=-1;
    for(int i=1;i<=tcnt;i++)
    {
        f[i][0]=i;
        _log[i]=(i&(i-1))==0?_log[i-1]+1:_log[i-1];
    }

    int t=_log[tcnt]+1;
    for(int j=1;j<=t;j++)
    {
        for(int i=1;i<=tcnt-(1<<j)+1;i++)
            f[i][j]=dd[f[i][j-1]]<dd[f[i+(1<<(j-1))][j-1]]?f[i][j-1]:f[i+(1<<(j-1))][j-1];

    }
}

int lca(int x,int y)
{
    if(id[x]>id[y]) swap(x,y);
    x=id[x],y=id[y];
    int k=_log[y-x+1];
    return dd[f[x][k]]<dd[f[y-(1<<k)+1][k]]?rk[f[x][k]]:rk[f[y-(1<<k)+1][k]];
}

int dis(int x,int y)
{
    return d[x]+d[y]-2*d[lca(x,y)];
}


struct node
{
    priority_queue<int>q1,q2;
    node(){}
    void clear()
    {
        while(q1.size()) q1.pop();
        while(q2.size()) q2.pop();
    }
    void push(int x)
    {
        q1.push(x);
    }
    void erase(int x)
    {
        q2.push(x);
    }
    int max(void)
    {
        while(q1.size()&&q2.size()&&q1.top()==q2.top()) q1.pop(),q2.pop();
        if(q1.size()) return q1.top();
        else return -inf;
    }
    int smax(void)
    {
        int now=max();
        if(now==-inf) return now;
        q1.pop();
        int nown=max();
        q1.push(now);
        return nown;
    }
}q1[maxn],q2[maxn],ans;

int maxpart[maxn],si[maxn],fa[maxn],last[maxn],lastq1[maxn];
bool ha[maxn];
int root,maxsi;
void dfs_size(int x,int fa)
{
    si[x]=1,maxpart[x]=0;
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa||ha[y]) continue;
        dfs_size(y,x);
        si[x]+=si[y];
        maxpart[x]=max(maxpart[x],si[y]);
    }
}
void dfs_root(int nowroot,int x,int fa)
{
    maxpart[x]=max(maxpart[x],si[nowroot]-si[x]);
    if(maxsi>maxpart[x])
    {
        maxsi=maxpart[x];
        root=x;
    }
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa||ha[y]) continue;
        dfs_root(nowroot,y,x);
    }
}

void dfs_dis(int rt,int x,int ffa)
{
    q1[rt].push(dis(x,fa[rt]));
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==ffa||ha[y]) continue;
        dfs_dis(rt,y,x);
    }
}

void dfs_for_tree(int x,int f)
{
    maxsi=inf;
    dfs_size(x,0);
    dfs_root(x,x,0);

    int rt=root;
    ha[rt]=true;
    fa[rt]=f;
    dfs_dis(rt,rt,0);
    lastq1[rt]=q1[rt].max();
    q2[f].push(q1[rt].max());
    q2[rt].push(0);
    for(int i=head[rt];i;i=nt[i])
    {
        int y=ver[i];
        if(ha[y]) continue;
        dfs_for_tree(y,rt);
    }
    ans.push(last[rt]=q2[rt].max()+q2[rt].smax());
}


void init(void)
{
    d[0]=-1;
    dfs(1,0);
    ST();

    dfs_for_tree(1,0);
}

bool isopen[maxn];
int close=0;

void get1(void)
{
    if(close==1) printf("0\n");
    else if(close==0) printf("-1\n");
    else printf("%d\n",ans.max());
}

void get2(int x)
{
    if(isopen[x]==false) q2[x].erase(0),close--;
    else q2[x].push(0),close++;
    int now,nowx=x;
    for(;x;x=fa[x])
    {
        ans.erase(last[x]);
        ans.push(last[x]=q2[x].max()+q2[x].smax());
        if(isopen[nowx]==false) q1[x].erase(dis(nowx,fa[x]));
        else q1[x].push(dis(nowx,fa[x]));
        q2[fa[x]].erase(lastq1[x]);
        q2[fa[x]].push(lastq1[x]=q1[x].max());
    }
    isopen[nowx]^=1;
}

int main(void)
{
    scanf("%d",&n);
    close=n;
    int x,y;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }

    init();

    char str[10];
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%s",str);
        if(str[0]=='G') get1();
        else
        {
            scanf("%d",&x);
            get2(x);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值