• CDOJ1425 Another LCIS [线段树]


      题目地址http://acm.uestc.edu.cn/problem.php?pid=1425

      题目分析:题目中给出N个数的一个序列S={S1,S2, ... ,SN}。又在这个序列上定义了两种操作:

        1. add 将区间[LR]内的数全部加上x

        2. query 询问在区间[LR]内,最大的上升子序列(CIS)的长度。

      这里LCIS是一段连续的序列,不同于LIS,后者可以跳过一些数。

      解题思路

        对区间的操作,自然想到线段树。

        我们在线段树seg[4*N+100]的节点中保存7个域:LRLlenRlenMaxLenaddlen。我们稍后看看如何对这7个域操作。先对这7个域描述一下:

          L:该区间左端点值;

          R:该区间右端点值;

          Llen:从左端点开始的LCIS的长度;

          Rlen:到右端点结束的LCIS的长度;

          MaxLen:包含在该区间内的LCIS的长度。

          add:该区间全部元素都要加上add

          len:仅仅在query函数的返回参数中有用。

       首先是对线段树的初始化了。我们将每个位置视为区间[LL+0]。从线段树根节点开始找下去,直到找到该区间,这时我们到达一个叶子节点,对该叶子节点初始化,再顺着路径返回到根节点。返回过程中在合适时候初始化中间节点。

      对叶子节点的初始化:(x为该点的值)

        L = R = x

        Llen = Rlen = MaxLen = 1

        add = 0

      对中间节点仅在其所有子节点都初始化后再进行初始化(这样所有中间节点都会初始化,且仅一次):

      此时根据其两个子节点seg[i*2]seg[i*2+1]进行初始化,以满足我们对节点各个域的描述(上面我们是如何描述这7个域的?)。

      下面描述updatequery

      我们先定义几个名词:

        包含节点:若要更新或查询的目标区间为[lr],满足l<=L && R<=r的区间 称为包含节点,此时该节点表示的区间完全包含在目标区间内。

        完全不包含节点:该节点表示的区间和目标区间没有交集。

        左子区间包含:该节点右子节点是完全不包含节点,左子节点不是。

        右子区间包含:该节点左子节点是完全不包含节点,右子节点不是。

     

      对区间的更新我们用update函数实现。

      我们注意到:

      1. 将一段区间每个数加上一个数x后,其内部的相对大小不改变,该区间对包含它的更大的区间的影响仅仅通过区间端点值LR实现。即在初始化和每次更新后,每个区间都能屏蔽其子区间对上面的影响。

      2. 对该区间的子区间查询结果,仅在返回到该节点之上更大的区间时,在该区间整体加上的值x会对返回结果产生影响。此时在返回至该区间时,对结果的端点值修饰(加上该区间的add值)即可。从上面的区间看下来,就像我们对每个子区间都更新了。

      从根节点开始,若遇到包含节点完成更新后就返回,遇到完全不包含区间直接返回。否则递归更新其左子节点、右子节点,直至到了一个包含节点或完全不包含节点。

    返回时,沿途更新所有节点。

      对包含节点的更新:L+=x、 R+=x、 add+=x

      对中间节点更新(返回时):更新其LlenRlenMaxLen,方法和初始化时是一样的。addlen不更新。跟新LR不是子区间端点值,而是子区间的端点值加上该节点的add,因为我们的子区间值可能被屏蔽了,不是最新的值。

     

     query函数完成查询。

      1.查询到包含节点:返回包含节点的值,并在len域注明区间长度

      2.查询到左子区间包含或右子区间包含的节点,仅对其左子节点或右子节点递归查询。对返回的结果修饰(结果的端点值LR加上该区间记录的add值)后,返回。

      3.其他情况既需对左子区间又需对右子区间查询,得到两个返回结果:ndjndk,将两个结果合并为一个结果,再对结果修饰(结果的端点值LR加上该区间记录的add值)后,返回。

    源代码

    #include<cstdio>
    #include<iostream>

    char chrn;
    #define SCRN while(scanf("%c",&ch) && ch!='\n');

    using namespace std;

    typedef struct
    {
    int Llen,Rlen,MaxLen,add,len,R,L;
    }node;

    node seg[400100];

    int max(int a,int b,int c,int d,int e)
    {
    int x=a;
    if(b>x)
    x=b;
    if(c>x)
    x=c;
    if(d>x)
    x=d;
    if(e>x)
    x=e;
    return x;
    }

    void ini(int i,int L,int R,int loc,int x)
    {
    int mid=(L+R)/2, j=2*i, k=j+1;
    int m;
    if(L==R)//leaf node
    {
    seg[i].Llen=1;
    seg[i].Rlen=1;
    seg[i].MaxLen=1;
    seg[i].L=x;
    seg[i].R=x;
    seg[i].add=0;
    return;
    }
    if(loc<=mid)
    ini(j,L,mid,loc,x);
    else
    ini(k,mid+1,R,loc,x);
    if(loc==R)//mid node
    {
    seg[i].L=seg[j].L;
    seg[i].R=seg[k].R;
    seg[i].add=0;
    if(seg[j].R < seg[k].L)
    {
    if(seg[j].Llen == mid-L+1)
    seg[i].Llen=seg[j].Llen+seg[k].Llen;
    else
    seg[i].Llen=seg[j].Llen;
    if(seg[k].Rlen == R-mid)
    seg[i].Rlen=seg[j].Rlen+seg[k].Rlen;
    else
    seg[i].Rlen=seg[k].Rlen;
    m=seg[j].Rlen+seg[k].Llen;
    }
    else
    {
    seg[i].Llen=seg[j].Llen;
    seg[i].Rlen=seg[k].Rlen;
    m=0;
    }
    seg[i].MaxLen = max(seg[i].Llen, seg[i].Rlen, seg[j].MaxLen, seg[k].MaxLen, m);
    }
    }

    void update(int i,int L,int R,int l,int r,int x)
    {
    int mid=(L+R)/2,j=2*i,k=j+1;
    int m;
    if(l<=L && R<=r)//included
    {
    seg[i].L+=x;
    seg[i].R+=x;
    seg[i].add+=x;
    return ;
    }
    else if(l>R || L>r)
    return ;
    update(j,L,mid,l,r,x);
    update(k,mid+1,R,l,r,x);

    //update
    seg[i].L=seg[j].L+seg[i].add;//关键要加上eg[i].add!!!!!!!!!!!!!!!!!!!!!!!!!!
    seg[i].R=seg[k].R+seg[i].add;
    if(seg[j].R < seg[k].L)
    {
    if(seg[j].Llen == mid-L+1)
    seg[i].Llen=seg[j].Llen+seg[k].Llen;
    else
    seg[i].Llen=seg[j].Llen;
    if(seg[k].Rlen == R-mid)
    seg[i].Rlen=seg[j].Rlen+seg[k].Rlen;
    else
    seg[i].Rlen=seg[k].Rlen;
    m=seg[j].Rlen+seg[k].Llen;
    }
    else
    {
    seg[i].Llen=seg[j].Llen;
    seg[i].Rlen=seg[k].Rlen;
    m=0;
    }
    seg[i].MaxLen = max(seg[i].Llen, seg[i].Rlen, seg[j].MaxLen, seg[k].MaxLen, m);
    }

    node query(int i,int L,int R,int l,int r)
    {
    int mid=(L+R)/2, j=i*2, k=j+1, m, add=seg[i].add;
    node ndj,ndk,nd;
    if(l<=L && R<=r)
    {
    nd=seg[i];
    nd.len=R-L+1;
    return nd;
    }
    else if(l>mid)
    {
    nd=query(k,mid+1,R,l,r);
    nd.L+=add;
    nd.R+=add;
    return nd;
    }
    else if(r<=mid)
    {
    nd=query(j,L,mid,l,r);
    nd.L+=add;
    nd.R+=add;
    return nd;
    }
    else
    {
    ndj=query(j,L,mid,l,r);
    ndk=query(k,mid+1,R,l,r);

    nd.L=ndj.L;
    nd.R=ndk.R;
    nd.len=ndj.len+ndk.len;
    if(ndj.R<ndk.L)
    {
    if(ndj.Llen == ndj.len)
    nd.Llen=ndj.Llen+ndk.Llen;
    else
    nd.Llen=ndj.Llen;
    if(ndk.Rlen == ndk.len)
    nd.Rlen=ndj.Rlen+ndk.Rlen;
    else
    nd.Rlen=ndk.Rlen;
    m=ndj.Rlen+ndk.Llen;
    }
    else
    {
    nd.Llen=ndj.Llen;
    nd.Rlen=ndk.Rlen;
    m=0;
    }
    nd.MaxLen = max(nd.Llen, nd.Rlen, ndj.MaxLen, ndk.MaxLen, m);

    nd.L+=add;
    nd.R+=add;
    return nd;
    }
    }

    int main()
    {
    int t,T,i,N,Q,r,l;
    int x;
    node nd;
    char ch;
    //freopen("1425in.txt","r",stdin);
    cin>>T;
    for(t=1; t<=T; t++)
    {
    cin>>N>>Q;
    for(i=0; i<=4*N; i++)
    {
    seg[i].add=0;
    seg[i].len=0;
    seg[i].Llen=seg[i].Rlen=seg[i].MaxLen=0;
    }
    for(i=1; i<=N; i++)
    {
    scanf("%d",&x);
    ini(1,1,N,i,x);
    }
    printf("Case #%d:\n",t);
    for(i=1; i<=Q; i++)
    {
    SCRN
    scanf("%c",&ch);
    if(ch=='a')
    {
    scanf("%d %d %d",&l,&r,&x);
    update(1,1,N,l,r,x);
    }
    else if(ch=='q')
    {
    scanf("%d %d",&l,&r);
    nd=query(1,1,N,l,r);
    printf("%d\n",nd.MaxLen);
    }
    }
    }
    return 0;
    }



  • 相关阅读:
    网络编程基础之TCP编程学习(一)
    日常巡检(脚本)
    Mysql主主配置
    创建用户和相对应的随机密码
    企业网络连接测试
    Docker 方式部署 Gitlab 并使用自定义的http端口
    Vue学习笔记(二):使用Axios进行跨域请求
    Vue学习笔记(一):引入Bootstrap和jQuery
    C# / .NET Core 调用javascript方法(适用于Windows/Linux平台)
    Centos7.7安装bcm43142(博通)无线网卡驱动
  • 原文地址:https://www.cnblogs.com/Lattexiaoyu/p/2413601.html
Copyright © 2020-2023  润新知