uestc 1425 Another LCIS(线段树 最长递增序列)

来源:互联网 发布:淘宝店铺的层级 编辑:程序博客网 时间:2024/05/16 06:43

Another LCIS

Time Limit: 1000 ms Memory Limit: 65536 kB Solved: 100 Tried: 1593

Description

For a sequence S1,S2,...,SN, and a pair of integers (i, j), if 1 <= i <= j <= N and Si < Si+1 < Si+2 <...< Sj-1 < Sj, then the sequence Si,Si+1,...,Sj is a CIS (Continuous Increasing Subsequence). The longest CIS of a sequence is called the LCIS (Longest Continuous Increasing Subsequence).

In this problem, we will give you a sequence first, and then some “add” operations and some “query” operations. An add operation adds a value to each member in a specified interval. For a query operation, you should output the length of the LCIS of a specified interval.

Input

The first line of the input is an integer T, which stands for the number of test cases you need to solve.

Every test case begins with two integers N, Q, where N is the size of the sequence, and Q is the number of queries. S1,S2,...,SNare specified on the next line, and then Q queries follow. Every query begins with a character ‘a’ or ‘q’. ‘a’ is followed by three integers L, R, V, meaning that add V to members in the interval [L, R] (including L, R), and ‘q’ is followed by two integers L, R, meaning that you should output the length of the LCIS of interval [L, R].

T <= 10;

1 <= N, Q <= 100000;

1 <= L <= R <= N;

-10000 <= S1,S2,...,SN, V <= 10000.

Output

For every test case, you should output "Case #k:" on a single line first, where k indicates the case number and starts at 1. Then for every ‘q’ query, output the answer on a single line. See sample for more details.

Simple Input

1
5 6
0 1 2 3 4 
q 1 4
a 1 2 -10
a 1 1 -6
a 5 5 -4
q 2 3
q 4 4

Simple Output

Case #1:
4
2
1

Source

The 9th UESTC Programming Contest Preliminary








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

题意:给你一个数列,每次回选择一个区间的数,或者把这些数都加上一个值,或者问你这些数的最长递增序列。。。

分析:这题对区间进行操作,很容易使我们想到线段树,但是,线段树要保存那些信息才能求得答案呢,成段的累加这个不是问题,只要加个延迟标记就行,最主要的是询问最长递增序列。。。

1.当然,我们肯定要保存区间的最大值,每次向上更新时,理首当然的取左右子树的最大值。。。但是如果两个区间合并出更长的序列呢?

2.保存每个区间左右边界的值,这个方便我们判断两个区间是否能合并,这样向上更新时就能知道是否会出现更优值了。。。

3.知道可能合并,那我们怎么求出现的更优值呢,当然,它会出现在中间,我们需要知道从左线段的右端可以到达的最左端 lmost,和右线段左端能到达的最右端rmost ,新的值就是 rmost-lmost+1,所以我们要保存所有线段左端点能到达的最右端,右端点能到达的最左端。。。。也就是lmost ,rmost

具体的实现看代码吧

代码:

#include<cstdio>#include<iostream>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;const int mm=111111;int dly[mm<<2],maxlen[mm<<2],vall[mm<<2],valr[mm<<2],rmost[mm<<2],lmost[mm<<2];void add(int rt,int val){    vall[rt]+=val,valr[rt]+=val;}void pushdown(int rt){    add(rt<<1,dly[rt]),add(rt<<1|1,dly[rt]);    dly[rt<<1]+=dly[rt],dly[rt<<1|1]+=dly[rt];    dly[rt]=0;}void pushup(int rt,int m){    maxlen[rt]=max(maxlen[rt<<1],maxlen[rt<<1|1]);    vall[rt]=vall[rt<<1],valr[rt]=valr[rt<<1|1];    rmost[rt]=rmost[rt<<1],lmost[rt]=lmost[rt<<1|1];    if(valr[rt<<1]<vall[rt<<1|1])    {        maxlen[rt]=max(maxlen[rt],rmost[rt<<1|1]-lmost[rt<<1]+1);        if(rmost[rt]>=m)rmost[rt]=rmost[rt<<1|1];        if(lmost[rt]<=m+1)lmost[rt]=lmost[rt<<1];    }}void build(int l,int r,int rt){    dly[rt]=0;    if(l==r)    {        scanf("%d",&vall[rt]);        valr[rt]=vall[rt];        rmost[rt]=r,lmost[rt]=l,maxlen[rt]=1;        return;    }    int m=(l+r)>>1;    build(lson);    build(rson);    pushup(rt,m);}void updata(int L,int R,int val,int l,int r,int rt){    if(L<=l&&R>=r)    {        add(rt,val);        dly[rt]+=val;        return;    }    int m=(l+r)>>1;    if(dly[rt])pushdown(rt);    if(L<=m)updata(L,R,val,lson);    if(R>m)updata(L,R,val,rson);    pushup(rt,m);}int query(int L,int R,int l,int r,int rt){    if(L<=l&&R>=r)return maxlen[rt];    int m=(l+r)>>1;    if(R<=m)return query(L,R,lson);    if(L>m)return query(L,R,rson);    int ret=max(query(L,R,lson),query(L,R,rson));    if(valr[rt<<1]<vall[rt<<1|1])ret=max(ret,min(R,rmost[rt<<1|1])-max(L,lmost[rt<<1])+1);    return ret;}int main(){    int i,j,k,n,m,t,cs;    char op[55];    scanf("%d",&t);    for(cs=1;cs<=t;++cs)    {        scanf("%d%d",&n,&m);        build(1,n,1);        printf("Case #%d:\n",cs);        while(m--)        {            scanf("%s%d%d",op,&i,&j);            if(op[0]=='q')printf("%d\n",query(i,j,1,n,1));            else            {                scanf("%d",&k);                updata(i,j,k,1,n,1);            }        }    }    return 0;}



原创粉丝点击