HDU_3308_线段树_区间合并

LCIS

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6166    Accepted Submission(s): 2675


Problem Description
Given n integers.
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].
 
Input
T in the first line, indicating the case number.
Each case starts with two integers n , m(0<n,m<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
OR
Q A B(0<=A<=B< n).
 
Output
For each Q, output the answer.
 
Sample Input
1 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9
 
Sample Output
1 1 4 2 3 1 2 5
 
第一道区间合并的线段树。

看了题解,从下午做到晚上。。。然而看网上说是一道简单的区间合并。。。桑心。。。

给出序列,可单点更新,求最长连续递增子列的长度。

每一段记录

struct Node
{
  int l,r,len;  //线段树中的左右端点,以及序列长度
  int ln,rn;   //这个线段上的序列左右端点
  int lm,rm,nm;   //包含左端点,包含右端点,整段的最长递增连续子列长度
} tree[maxn<<2];

一个序列(rt)中的最长连续递增子列的长度(nm)是 max(tree[rt<<1].nm,tree[rt<<1|1].nm)和满足tree[rt<<1].rn<tree[rt<<1|1].ln(左孩子的右端点小于右孩子的左端点)条件下的tree[rt<<1].rm+tree[rt<<1|1].lm中较大者。更新点后pushup和query就是用这个思想。

第一波超时,是因为mid=(l+r)/2,用位运算更快,mid=(l+r)>>1

之前查询函数写的有问题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100005
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

struct Node
{
    int l,r,len;
    int ln,rn;
    int lm,rm,nm;
} tree[maxn<<2];

int num[100005];

void pushup(int rt)
{
    tree[rt].ln=tree[rt<<1].ln;
    tree[rt].rn=tree[rt<<1|1].rn;
    tree[rt].lm=tree[rt<<1].lm;
    tree[rt].rm=tree[rt<<1|1].rm;
    tree[rt].nm=max(tree[rt<<1].nm,tree[rt<<1|1].nm);
    if(tree[rt<<1].rn<tree[rt<<1|1].ln)
    {
        if(tree[rt].lm==tree[rt<<1].len)
            tree[rt].lm+=tree[rt<<1|1].lm;
        if(tree[rt].rm==tree[rt<<1|1].len)
            tree[rt].rm+=tree[rt<<1].rm;
        tree[rt].nm=max(tree[rt].nm,tree[rt<<1].rm+tree[rt<<1|1].lm);
    }
}

void build(int l,int r,int rt)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].len=r-l+1;
    if(l==r)
    {
        tree[rt].lm=tree[rt].rm=tree[rt].nm=1;
        tree[rt].ln=tree[rt].rn=num[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void update(int pos,int x,int l,int r,int rt)
{
    if(l==pos&&r==pos)
    {
        tree[rt].ln=tree[rt].rn=x;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        update(pos,x,lson);
    else
        update(pos,x,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)
        return tree[rt].nm;
    int mid=(l+r)>>1;
    if(R<=mid)
        return query(L,R,lson);
    else if(L>mid)
        return query(L,R,rson);
    else
    {
        int ll=query(L,mid,lson),ans=0;
        int rr=query(mid+1,R,rson);
        if(tree[rt<<1].rn<tree[rt<<1|1].ln)
            ans=min(mid-L+1,tree[rt<<1].rm)+min(R-mid,tree[rt<<1|1].lm);
        return max(ans,max(ll,rr));
    }
}
/*
int query(int l,int r,int i)//查询最大的LCIS
{
    if(tree[i].l>=l && tree[i].r<=r)
    {
        return tree[i].nm;
    }
    int mid = (tree[i].l+tree[i].r)>>1,ans = 0;
    if(l<=mid)
        ans = max(ans,query(l,r,2*i));
    if(r>mid)
        ans = max(ans,query(l,r,2*i+1));
    if(tree[2*i].rn < tree[2*i+1].ln)
        ans = max(ans , min(mid-l+1,tree[2*i].rm)+min(r-mid,tree[2*i+1].lm));
    return ans;
}*/

int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            scanf("%d",&num[i]);
        build(1,n,1);
        //cout<<tree[9].nm<<endl;
        //cout<<"*"<<endl;

        for(int i=0; i<m; i++)
        {
            char str[2];
            int a,b;
            scanf("%s%d%d",str,&a,&b);
            if(str[0]=='U')
                update(a+1,b,1,n,1);
            else if(str[0]=='Q')
                printf("%d
",query(a+1,b+1,1,n,1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jasonlixuetao/p/5510626.html