首页 > 代码库 > 【BZOJ】1984 月下“毛景树”

【BZOJ】1984 月下“毛景树”

【算法】树链剖分+线段树

【题解】线段树的区间加值和区间覆盖操作不能同时存在,只能存在一个。

修改:从根节点跑到目标区域路上的标记全部下传,打完标记再上传回根节点(有变动才需要上传)。

询问:访问到目标区域路上的标记全部下传。

我写的线段树版本是在打标记的同时便对该点的询问项(最大值)做了对应更改,即可保证访问到该点得到的ms就是该点的答案。

访问某点时如果要询问最大值就直接拿走,如果要还要访问该点的子节点就需要下传。

而修改了某点的值,它的祖先的值就都需要变动,所以一旦修改必须上传至顶。

对于add和cover不共存的问题,下传过程:

void pushdown(int k)
{
    if(t[k].l==t[k].r)return;
    if(t[k].c!=-1)
     {
         t[k<<1].a=t[k<<1|1].a=0;
         t[k<<1].c=t[k<<1|1].c=t[k].c;
         t[k<<1].ms=t[k<<1|1].ms=t[k].c;
         t[k].c=-1;
     }
    if(t[k].a!=0)
     {
         if(t[k<<1].c!=-1)t[k<<1].c+=t[k].a;
          else t[k<<1].a+=t[k].a;
         if(t[k<<1|1].c!=-1)t[k<<1|1].c+=t[k].a;
          else t[k<<1|1].a+=t[k].a;
         t[k<<1].ms+=t[k].a;t[k<<1|1].ms+=t[k].a;
         t[k].a=0;
     }
}

下传cover时,子树add‘=0,cover‘=cover,ms=cover

下传add时,就要看子树的标记是cover还是add了。

边权赋给下面的点,注意LCA不算(树剖过程中顺便处理即可,不必写倍增)

不在同一条重链时,是deep[top[u]]大的先,不是deep[u]。

技术分享
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=200010,inf=0x3f3f3f3f;
struct tree{int l,r,c,a,ms;}t[maxn*3];
struct edge{int v,w,from;}e[maxn*3];
int dfsnum,n,pos[maxn],size[maxn],first[maxn],deep[maxn],f[maxn],id[maxn*3],tot,top[maxn];
void insert(int u,int v,int w)
{tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
void build(int k,int l,int r)
{
    t[k].l=l;t[k].r=r;t[k].c=-1;
    if(l!=r)
     {
         int mid=(l+r)>>1;
         build(k<<1,l,mid);
         build(k<<1|1,mid+1,r);
     }
}
void pushdown(int k)
{
    if(t[k].l==t[k].r)return;
    if(t[k].c!=-1)
     {
         t[k<<1].a=t[k<<1|1].a=0;
         t[k<<1].c=t[k<<1|1].c=t[k].c;
         t[k<<1].ms=t[k<<1|1].ms=t[k].c;
         t[k].c=-1;
     }
    if(t[k].a!=0)
     {
         if(t[k<<1].c!=-1)t[k<<1].c+=t[k].a;
          else t[k<<1].a+=t[k].a;
         if(t[k<<1|1].c!=-1)t[k<<1|1].c+=t[k].a;
          else t[k<<1|1].a+=t[k].a;
         t[k<<1].ms+=t[k].a;t[k<<1|1].ms+=t[k].a;
         t[k].a=0;
     }
}
void pushup(int k)
{
    t[k].ms=max(t[k<<1].ms,t[k<<1|1].ms);
}
void cover(int k,int l,int r,int x)
{
    int left=t[k].l,right=t[k].r;
    pushdown(k);
    if(l<=left&&right<=r)t[k].c=x,t[k].ms=x;
     else
      {
          int mid=(left+right)>>1;
          if(l<=mid)cover(k<<1,l,r,x);
          if(r>mid)cover(k<<1|1,l,r,x);
          pushup(k);
      }
}
void add(int k,int l,int r,int x)
{
    int left=t[k].l,right=t[k].r;
    pushdown(k);
    if(l<=left&&right<=r)t[k].a+=x,t[k].ms+=x;
     else
      {
          int mid=(left+right)>>1;
          if(l<=mid)add(k<<1,l,r,x);
          if(r>mid)add(k<<1|1,l,r,x);
          pushup(k);
      }
}
int ask(int k,int l,int r)
{
    int left=t[k].l,right=t[k].r;
    if(l<=left&&right<=r)return t[k].ms;
     else
      {
          int mid=(left+right)>>1;
          pushdown(k);int mss=-inf;
          if(l<=mid)mss=ask(k<<1,l,r);
          if(r>mid)mss=max(mss,ask(k<<1|1,l,r));
          return mss;
      }
}
void solve_cover()
{
    int u,v,w;
    scanf("%d%d%d",&u,&v,&w);
    while(top[u]!=top[v])
     {
         if(deep[top[u]]<deep[top[v]])swap(u,v);
         cover(1,pos[top[u]],pos[u],w);
         u=f[top[u]];
     }
    if(pos[u]>pos[v])swap(u,v);
    if(pos[u]<pos[v])cover(1,pos[u]+1,pos[v],w);
}
void solve_add()
{
    int u,v,w;
    scanf("%d%d%d",&u,&v,&w);
    while(top[u]!=top[v])
     {
       if(deep[top[u]]<deep[top[v]])swap(u,v);
         add(1,pos[top[u]],pos[u],w);
         u=f[top[u]];
     }
    if(pos[u]>pos[v])swap(u,v);
    if(pos[u]<pos[v])add(1,pos[u]+1,pos[v],w);
}
void ask_max()
{
    int u,v;
    scanf("%d%d",&u,&v);
    int maxs=-inf;
    while(top[u]!=top[v])
     {
         if(deep[top[u]]<deep[top[v]])swap(u,v);
         maxs=max(maxs,ask(1,pos[top[u]],pos[u]));
         u=f[top[u]];
     }
    if(pos[u]>pos[v])swap(u,v);
    if(pos[u]<pos[v])maxs=max(maxs,ask(1,pos[u]+1,pos[v]));
    printf("%d\n",maxs);
}
void dfs1(int x,int fa)
{
    size[x]=1;
    for(int i=first[x];i;i=e[i].from)
     if(e[i].v!=fa)
      {
          int y=e[i].v;
          deep[y]=deep[x]+1;
          f[y]=x;
          dfs1(y,x);
          size[x]+=size[y];
      }
}
void dfs2(int x,int tp,int fa)
{
    pos[x]=++dfsnum;
    top[x]=tp;
    int k=0;
    for(int i=first[x];i;i=e[i].from)
     if(e[i].v!=fa){if(size[e[i].v]>size[k])k=e[i].v;}
      else id[(i+1)>>1]=x,add(1,pos[x],pos[x],e[i].w);
    if(k==0)return;//!!!
    dfs2(k,tp,x);
    for(int i=first[x];i;i=e[i].from)
     if(e[i].v!=fa&&e[i].v!=k)dfs2(e[i].v,e[i].v,x);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
     {
         int u,v,w;
         scanf("%d%d%d",&u,&v,&w);
         insert(u,v,w);
         insert(v,u,w);
     }
    build(1,1,n);
    dfs1(1,-1);
    dfs2(1,1,-1);
    char st[10];int u,v;
    for(;;)
     {
         scanf("%s",st);
         if(st[1]==h)//change
          {
              scanf("%d%d",&u,&v);
              cover(1,pos[id[u]],pos[id[u]],v);
          }
         if(st[1]==o)solve_cover();//cover
         if(st[1]==d)solve_add();//add
         if(st[1]==a)ask_max();//max
         if(st[1]==t)break;//stop
     }
    return 0;
}
View Code

 

【BZOJ】1984 月下“毛景树”