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].
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).
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\n",query(a+1,b+1,1,n,1)); } } return 0; }