您的位置:首页 > 其它

hdu 3308 线段树-区间连续最长上升子序列

2015-05-01 13:40 411 查看

LCIS

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 4842    Accepted Submission(s): 2166


[align=left]Problem Description[/align]
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].

 

[align=left]Input[/align]
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).

 

[align=left]Output[/align]
For each Q, output the answer.
 

[align=left]Sample Input[/align]

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

 

[align=left]Sample Output[/align]

1
1
4
2
3
1
2
5

求区间连续最长子序列,用线段树分治的思想做。某个区间的[l,r]的最长子序列,将区间分解成两部分,最长部分可能在[l,m]、[m+1,r]、或者部分在左半部部分在右半部份。

对于第三种情况,其长度为左半部分的右端点开始逆向的最长下降长度+右半部份的左端点为起点的最长上升长度(前提a[m]<a[m+1])。

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
using namespace std;

#define maxn 300005
#define getc int m=(l+r)>>1, lc=rt<<1,rc=rt<<1|1

int lk[maxn],rk[maxn],ls[maxn],rs[maxn],s[maxn];
int a[maxn/3];

void push_up(int rt, int l, int r)
{
getc;
lk[rt]=lk[lc],rk[rt]=rk[rc];
s[rt]=max(s[lc], s[rc]);
if(rk[lc]<lk[rc])
s[rt]=max(s[rt], rs[lc]+ls[rc]);
ls[rt]=ls[lc];
if(ls[lc]==m-l+1 && rk[lc]<lk[rc])
ls[rt]=ls[lc]+ls[rc];
rs[rt]=rs[rc];
if(rs[rc]==r-m && rk[lc]<lk[rc])
rs[rt]=rs[rc]+rs[lc];
}
void build(int rt, int l, int r)
{
if(l==r){
lk[rt]=rk[rt]=a[l];
s[rt]=ls[rt]=rs[rt]=1;
return;
}
getc;
build(lc, l, m);
build(rc, m+1, r);
push_up(rt, l, r);
}

void update(int rt, int l, int r, int k, int v)
{
if(l==r){
lk[rt]=rk[rt]=v;
s[rt]=ls[rt]=rs[rt]=1;
return;
}
getc;
if(k<=m)
update(lc, l, m, k, v);
else
update(rc, m+1, r, k, v);
push_up(rt, l, r);
}

int lquery(int rt, int l, int r, int ll, int rr)
{
if(ll<=l && r<=rr){
return ls[rt];
}
getc;
int ret=lquery(lc, l, m, ll, min(rr, m));
if(rr>m && ret==m-l+1 && rk[lc]<lk[rc])
ret+=lquery(rc, m+1, r, m+1, rr);
return ret;
}
int rquery(int rt, int l, int r, int ll, int rr)
{
if(ll<=l && r<=rr){
return rs[rt];
}
getc;
int ret=rquery(rc, m+1, r, max(ll, m+1), rr);
if(ll<=m && ret==r-m && rk[lc]<lk[rc])
ret+=rquery(lc, l, m, ll, m);
return ret;
}

int query(int rt, int l, int r, int ll, int rr)
{
if(ll<=l && r<=rr){
return s[rt];
}
getc;
if(rr<=m)
return query(lc, l, m, ll, rr);
else if(ll>m)
return query(rc, m+1, r, ll, rr);
else{
int ret=max(query(lc, l, m, ll, m), query(rc, m+1, r, m+1, rr));
if(rk[lc]<lk[rc])
ret=max(ret, rquery(lc, l, m, ll, m)+lquery(rc, m+1, r, m+1, rr));
return ret;
}
}

int main()
{
int t;
scanf("%d", &t);
while(t--){
int n,m;
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
scanf("%d", a+i);
build(1, 1, n);
char s[3];
int a,b;
while(m--){
scanf("%s%d%d", s, &a,&b);
a++;
if(s[0]=='U'){
update(1, 1,n, a, b);
}
else{
b++;
printf("%d\n", query(1, 1, n, a,b));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树