1. 程式人生 > >【題解】Luogu P4679 [ZJOI2011]道館之戰

【題解】Luogu P4679 [ZJOI2011]道館之戰

原題傳送門

碼農題樹剖好題

這道題要用樹鏈剖分(好像也有神仙用LCT),我部落格裡有對樹鏈剖分的詳細介紹

考慮在鏈上的情況,在當前考慮的區間中,令dis[0][0]表示從左上走到右上的最長路,dis[0][1]表示從左上到右下,dis[1][0],dis[1][1]以此類推. 令maxx[0][0]表示從左上出發能走的最大距離,maxx[0][1]表示左下的,maxx[1][0]表示右上,maxx[1][1]表示右下.它們的合併比較簡單.令當前區間為c,左半區間為a,右半區間為b,那麼:

    c.dis[0][0]=Max(-inf,Max(a.dis[0][0]+b.dis[0][0],a.dis[0][1]+b.dis[1][0]));
    c.dis[0][1]=Max(-inf,Max(a.dis[0][0]+b.dis[0][1],a.dis[0][1]+b.dis[1][1]));
    c.dis[1][0]=Max(-inf,Max(a.dis[1][1]+b.dis[1][0],a.dis[1][0]+b.dis[0][0]));
    c.dis[1][1]=Max(-inf,Max(a.dis[1][1]+b.dis[1][1],a.dis[1][0]+b.dis[0][1]));
    c.maxx[0][0]=Max(a.maxx[0][0],Max(a.dis[0][0]+b.maxx[0][0],a.dis[0][1]+b.maxx[0][1]));
    c.maxx[0][1]=Max(a.maxx[0][1],Max(a.dis[1][0]+b.maxx[0][0],a.dis[1][1]+b.maxx[0][1]));
    c.maxx[1][0]=Max(b.maxx[1][0],Max(b.dis[0][0]+a.maxx[1][0],b.dis[1][0]+a.maxx[1][1]));
    c.maxx[1][1]=Max(b.maxx[1][1],Max(b.dis[0][1]+a.maxx[1][0],b.dis[1][1]+a.maxx[1][1]));

在樹上怎麼辦呢?每次詢問的是兩個點之間的路徑,很顯然,要用線段樹+樹鏈剖分. 如果詢問的兩個點分別是x,y,令lans表示x向上跳得到的答案,rans表示y向上跳得到的答案,最後要將lans取反再與rans合併,因為當兩個點最後跳到一起時,它們的左端點對應左端點,右端點對應右端點,而我們要求左端點對應右端點,右端點對應左端點,所以要取反(這個珂以畫個圖理解一下子)

#include <bits/stdc++.h>
#define N 50005
#define inf (1<<30)
using namespace std;
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline void Swap(register int &a,register int &b)
{
    a^=b^=a^=b;
}
inline int Max(register int x,register int y)
{
    return x>y?x:y;
}
struct edge{
    int to,next;
}eg[N<<1];
int head[N],cnt=0;
inline void add(register int u,register int v)
{
    eg[++cnt]=(edge){v,head[u]};
    head[u]=cnt;
}
int n,m;
int size[N],dep[N],fa[N],son[N];
int tot=0,dl[N],id[N],top[N];
int a[N][2]; 
inline void dfs1(register int x,register int faa)
{
    fa[x]=faa;
    size[x]=1;
    dep[x]=dep[faa]+1;
    for(register int i=head[x];i;i=eg[i].next)
    {
        int v=eg[i].to;
        if(v==faa)
            continue;
        dfs1(v,x);
        size[x]+=size[v];
        if(size[v]>size[son[x]])
            son[x]=v;
    }
}
inline void dfs2(register int x,register int t)
{
    dl[x]=++tot;
    id[tot]=x;
    top[x]=t;
    if(son[x])
        dfs2(son[x],t);
    for(register int i=head[x];i;i=eg[i].next)
    {
        int v=eg[i].to;
        if(v==fa[x]||v==son[x])
            continue;
        dfs2(v,v);
    }
}
struct node{
    int dis[2][2],maxx[2][2];
    inline void clear()
    {
        memset(dis,0,sizeof(dis));
        memset(maxx,0,sizeof(maxx));
    }
    inline bool emptyy()
    {
        if(!dis[0][0]&&!dis[0][1]&&!dis[1][0]&&!dis[1][1]&&!maxx[0][0]&&!maxx[0][1]&&!maxx[1][0]&&!maxx[1][1])
            return true;
        return false;
    }
}e[N<<2];
inline node pushup(register node a,register node b)
{
    node c;
    if(a.emptyy())
        c=b;
    else if(b.emptyy())
        c=a;
    else
    {
        c.dis[0][0]=Max(-inf,Max(a.dis[0][0]+b.dis[0][0],a.dis[0][1]+b.dis[1][0]));
        c.dis[0][1]=Max(-inf,Max(a.dis[0][0]+b.dis[0][1],a.dis[0][1]+b.dis[1][1]));
        c.dis[1][0]=Max(-inf,Max(a.dis[1][1]+b.dis[1][0],a.dis[1][0]+b.dis[0][0]));
        c.dis[1][1]=Max(-inf,Max(a.dis[1][1]+b.dis[1][1],a.dis[1][0]+b.dis[0][1]));
        c.maxx[0][0]=Max(a.maxx[0][0],Max(a.dis[0][0]+b.maxx[0][0],a.dis[0][1]+b.maxx[0][1]));
        c.maxx[0][1]=Max(a.maxx[0][1],Max(a.dis[1][0]+b.maxx[0][0],a.dis[1][1]+b.maxx[0][1]));
        c.maxx[1][0]=Max(b.maxx[1][0],Max(b.dis[0][0]+a.maxx[1][0],b.dis[1][0]+a.maxx[1][1]));
        c.maxx[1][1]=Max(b.maxx[1][1],Max(b.dis[0][1]+a.maxx[1][0],b.dis[1][1]+a.maxx[1][1]));
    }
    return c;
}
inline void build(register int x,register int l,register int r)
{
    if(l==r)
    {
        int p=a[id[l]][0],q=a[id[l]][1];
        if(p==1&&q==1)
        {
            e[x].dis[0][0]=e[x].dis[1][1]=1;
            e[x].dis[0][1]=e[x].dis[1][0]=2;
            e[x].maxx[0][0]=e[x].maxx[0][1]=e[x].maxx[1][0]=e[x].maxx[1][1]=2;
        }
        else if(p==1)
        {
            e[x].dis[0][0]=1;
            e[x].dis[0][1]=e[x].dis[1][0]=e[x].dis[1][1]=-inf;
            e[x].maxx[0][0]=e[x].maxx[1][0]=1;
            e[x].maxx[0][1]=e[x].maxx[1][1]=-inf;
        }
        else if(q==1)
        {
            e[x].dis[0][0]=e[x].dis[0][1]=e[x].dis[1][0]=-inf;
            e[x].dis[1][1]=1;
            e[x].maxx[0][0]=e[x].maxx[1][0]=-inf;
            e[x].maxx[0][1]=e[x].maxx[1][1]=1;
        }
        else
        {
            for(register int i=0;i<=1;++i)
                for(register int j=0;j<=1;++j)
                    e[x].dis[i][j]=e[x].maxx[i][j]=-inf;
        }
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    e[x]=pushup(e[x<<1],e[x<<1|1]);
}
inline void update(register int x,register int l,register int r,register int v,register int p,register int q)
{
    if(l==r)
    {
        if(p==1&&q==1)
        {
            e[x].dis[0][0]=e[x].dis[1][1]=1;
            e[x].dis[0][1]=e[x].dis[1][0]=2;
            e[x].maxx[0][0]=e[x].maxx[0][1]=e[x].maxx[1][0]=e[x].maxx[1][1]=2;
        }
        else if(p==1)
        {
            e[x].dis[0][0]=1;
            e[x].dis[0][1]=e[x].dis[1][0]=e[x].dis[1][1]=-inf;
            e[x].maxx[0][0]=e[x].maxx[1][0]=1;
            e[x].maxx[0][1]=e[x].maxx[1][1]=-inf;
        }
        else if(q==1)
        {
            e[x].dis[0][0]=e[x].dis[0][1]=e[x].dis[1][0]=-inf;
            e[x].dis[1][1]=1;
            e[x].maxx[0][0]=e[x].maxx[1][0]=-inf;
            e[x].maxx[0][1]=e[x].maxx[1][1]=1;
        }
        else
        {
            for(register int i=0;i<=1;++i)
                for(register int j=0;j<=1;++j)
                    e[x].dis[i][j]=e[x].maxx[i][j]=-inf;
        }
        return;
    }
    int mid=l+r>>1;
    if(v<=mid)
        update(x<<1,l,mid,v,p,q);
    else
        update(x<<1|1,mid+1,r,v,p,q);
    e[x]=pushup(e[x<<1],e[x<<1|1]);
}
inline node rev(register node a)
{
    Swap(a.maxx[0][0],a.maxx[1][0]);
    Swap(a.maxx[0][1],a.maxx[1][1]);
    Swap(a.dis[0][1],a.dis[1][0]);
    return a;
}
inline node query(register int x,register int l,register int r,register int L,register int R)
{
    if(l==L&&r==R)
        return e[x];
    int mid=l+r>>1;
    if(R<=mid)
        return query(x<<1,l,mid,L,R);
    else if(L>mid)
        return query(x<<1|1,mid+1,r,L,R);
    else
        return pushup(query(x<<1,l,mid,L,mid),query(x<<1|1,mid+1,r,mid+1,R));
}
inline int Query(register int x,register int y)
{
    node lans,rans;
    lans.clear();
    rans.clear();
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
        {
            rans=pushup(query(1,1,n,dl[top[y]],dl[y]),rans);
            y=fa[top[y]];
        }
        else
        {
            lans=pushup(query(1,1,n,dl[top[x]],dl[x]),lans);
            x=fa[top[x]];
        }
    }
    if(dep[x]>dep[y])
        lans=pushup(query(1,1,n,dl[y],dl[x]),lans);
    else
        rans=pushup(query(1,1,n,dl[x],dl[y]),rans);
    lans=pushup(rev(lans),rans);
    int res=Max(lans.maxx[0][0],lans.maxx[0][1]);
    return res<0?0:res;
}
int main()
{
    n=read(),m=read();
    for(register int i=1;i<n;++i)
    {
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(register int i=1;i<=n;++i)
    {
        char ch[3];
        scanf("%s",ch);
        a[i][0]=(ch[0]=='.')?1:0;
        a[i][1]=(ch[1]=='.')?1:0;
    }
    build(1,1,n);
    while(m--)
    {
        char c=getchar();
        while(c!='C'&&c!='Q')
            c=getchar();
        if(c=='C')
        {
            int u=read();
            char s[3];
            scanf("%s",s);
            int p=(s[0]=='.')?1:0,q=(s[1]=='.')?1:0;
            update(1,1,n,dl[u],p,q);
        }
        else
        {
            int u=read(),v=read();
            write(Query(u,v)),puts("");
        }
    } 
    return 0;
}