题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2325

题解

假设地图2×n2\times n,没有修改操作,那么可以设len[l][r][a][b]len[l][r][a][b]表示l,rl,r这一段从(a,l)(a,l)(b,r)(b,r),最多可以经过多少个冰块,far[l][r][a][b]far[l][r][a][b]表示l,rl,r这一段从(a,{lb=0rb=1)(a,\begin{cases}l&b=0\\ r&b=1\end{cases})开始最多能走多远。

转移显然(逃

但是这样显然太慢了,因此我们可以用线段树来优化

但是带修改怎么办?线段树单点修改,可以证明不会影响到其他的点。

但是原题是在树上,因此可以用树剖来解决。

代码

#include <cstdio>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=50000;
const int inf=0x3f3f3f3f;

struct data
{
  int len[2][2],far[2][2];

  data()
  {
    len[0][0]=len[0][1]=len[1][0]=len[1][1]=far[0][0]=far[1][0]=far[0][1]=far[1][1]=0;
  }

  data operator +(const data &other) const
  {
    if(((*this).len[0][0]==0)&&((*this).len[0][1]==0)&&((*this).len[1][0]==0)&&((*this).len[1][1]==0)&&((*this).far[0][0]==0)&&((*this).far[0][1]==0)&&((*this).far[1][0]==0)&&((*this).far[1][1]==0))
      {
        return other;
      }
    if((other.len[0][0]==0)&&(other.len[0][1]==0)&&(other.len[1][0]==0)&&(other.len[1][1]==0)&&(other.far[0][0]==0)&&(other.far[0][1]==0)&&(other.far[1][0]==0)&&(other.far[1][1]==0))
      {
        return (*this);
      }
    data ans;
    ans.len[0][0]=std::max(len[0][0]+other.len[0][0],len[0][1]+other.len[1][0]);
    if(ans.len[0][0]<0)
      {
        ans.len[0][0]=-inf;
      }
    ans.len[0][1]=std::max(len[0][0]+other.len[0][1],len[0][1]+other.len[1][1]);
    if(ans.len[0][1]<0)
      {
        ans.len[0][1]=-inf;
      }
    ans.len[1][0]=std::max(len[1][0]+other.len[0][0],len[1][1]+other.len[1][0]);
    if(ans.len[1][0]<0)
      {
        ans.len[1][0]=-inf;
      }
    ans.len[1][1]=std::max(len[1][0]+other.len[0][1],len[1][1]+other.len[1][1]);
    if(ans.len[1][1]<0)
      {
        ans.len[1][1]=-inf;
      }
    ans.far[0][0]=std::max(far[0][0],std::max(len[0][0]+other.far[0][0],len[0][1]+other.far[0][1]));
    if(ans.far[0][0]<0)
      {
        ans.far[0][0]=-inf;
      }
    ans.far[0][1]=std::max(far[0][1],std::max(len[1][0]+other.far[0][0],len[1][1]+other.far[0][1]));
    if(ans.far[0][1]<0)
      {
        ans.far[0][1]=-inf;
      }
    ans.far[1][0]=std::max(other.far[1][0],std::max(other.len[0][0]+far[1][0],other.len[1][0]+far[1][1]));
    if(ans.far[1][0]<0)
      {
        ans.far[1][0]=-inf;
      }
    ans.far[1][1]=std::max(other.far[1][1],std::max(other.len[0][1]+far[1][0],other.len[1][1]+far[1][1]));
    if(ans.far[1][1]<0)
      {
        ans.far[1][1]=-inf;
      }
    return ans;
  }
};

char mp[maxn+10][2],s[10];

namespace sgt
{
  data val[maxn<<2];

  int updata(int x)
  {
    val[x]=val[x<<1]+val[x<<1|1];
    return 0;
  }

  int modify(int x,int l,int r,int pos)
  {
    if(l==r)
      {
        val[x].len[0][0]=val[x].far[0][0]=val[x].far[1][0]=(mp[pos][0]=='.')?1:-inf;
        val[x].len[1][1]=val[x].far[0][1]=val[x].far[1][1]=(mp[pos][1]=='.')?1:-inf;
        val[x].len[0][1]=val[x].len[1][0]=((mp[pos][0]=='.')&&(mp[pos][1]=='.'))?2:-inf;
        if((mp[pos][0]=='.')&&(mp[pos][1]=='.'))
          {
            val[x].far[0][0]=val[x].far[1][0]=val[x].far[0][1]=val[x].far[1][1]=2;
          }
        return 0;
      }
    int mid=(l+r)>>1;
    if(pos<=mid)
      {
        modify(x<<1,l,mid,pos);
      }
    else
      {
        modify(x<<1|1,mid+1,r,pos);
      }
    updata(x);
    return 0;
  }

  data getval(int x,int l,int r,int askl,int askr)
  {
    if((askl<=l)&&(r<=askr))
      {
        return val[x];
      }
    int mid=(l+r)>>1;
    data ans;
    if(askl<=mid)
      {
        ans=ans+getval(x<<1,l,mid,askl,askr);
      }
    if(mid<askr)
      {
        ans=ans+getval(x<<1|1,mid+1,r,askl,askr);
      }
    return ans;
  }
}

int n,m,pre[maxn*2+10],now[maxn+10],son[maxn*2+10],tot,deep[maxn+10],dfn[maxn+10],top[maxn+10],wson[maxn+10],fa[maxn+10],size[maxn+10],cnt;

int ins(int a,int b)
{
  pre[++tot]=now[a];
  now[a]=tot;
  son[tot]=b;
  return 0;
}

int dfsfirst(int u,int father)
{
  fa[u]=father;
  deep[u]=deep[father]+1;
  size[u]=1;
  for(int i=now[u]; i; i=pre[i])
    {
      int v=son[i];
      if(v!=father)
        {
          dfsfirst(v,u);
          size[u]+=size[v];
          if((wson[u]==0)||(size[wson[u]]<size[v]))
            {
              wson[u]=v;
            }
        }
    }
  return 0;
}

int dfssecond(int u,int topfather)
{
  dfn[u]=++cnt;
  top[u]=topfather;
  if(wson[u]==0)
    {
      return 0;
    }
  dfssecond(wson[u],topfather);
  for(int i=now[u]; i; i=pre[i])
    {
      int v=son[i];
      if((v!=fa[u])&&(v!=wson[u]))
        {
          dfssecond(v,v);
        }
    }
  return 0;
}

int getlca(int x,int y)
{
  while(top[x]!=top[y])
    {
      if(deep[top[x]]<deep[top[y]])
        {
          std::swap(x,y);
        }
      x=fa[top[x]];
    }
  if(deep[x]>deep[y])
    {
      std::swap(x,y);
    }
  return x;
}

data getval(int x,int f,int flag)
{
  data ans;
  while(top[x]!=top[f])
    {
      ans=sgt::getval(1,1,n,dfn[top[x]],dfn[x])+ans;
      x=fa[top[x]];
    }
  if(flag)
    {
      ans=sgt::getval(1,1,n,dfn[f],dfn[x])+ans;
    }
  else
    {
      if(dfn[f]+1<=dfn[x])
        {
          ans=sgt::getval(1,1,n,dfn[f]+1,dfn[x])+ans;
        }
    }
  return ans;
}

int solve(int x,int y)
{
  int lca=getlca(x,y);
  data l=getval(x,lca,1),r=getval(y,lca,0);
  std::swap(l.len[0][1],l.len[1][0]);
  std::swap(l.far[0][0],l.far[1][0]);
  std::swap(l.far[0][1],l.far[1][1]);
  data ans=l+r;
  return std::max(ans.far[0][0],ans.far[0][1]);
}

int main()
{
  n=read();
  m=read();
  for(int i=1; i<n; ++i)
    {
      int a=read(),b=read();
      ins(a,b);
      ins(b,a);
    }
  dfsfirst(1,0);
  dfssecond(1,1);
  for(int i=1; i<=n; ++i)
    {
      scanf("%s",mp[dfn[i]]);
      sgt::modify(1,1,n,dfn[i]);
    }
  while(m--)
    {
      scanf("%s",s+1);
      if(s[1]=='Q')
        {
          int a=read(),b=read();
          int ans=solve(a,b);
          if(ans<0)
            {
              ans=0;
            }
          printf("%d\n",ans);
        }
      else
        {
          int pos=read();
          scanf("%s",mp[dfn[pos]]);
          sgt::modify(1,1,n,dfn[pos]);
        }
    }
  return 0;
}