瑤瑤想要玩滑梯
Problem Description
衆所周知,瑤瑤(tsyao)是個貪玩的萌妹子,特別喜歡鬧騰,恰好今天是一個風和日麗的日子,瑤瑤嚷着讓姐姐帶她去去公園玩滑梯,可是公園的滑梯比較獨特,由單位積木搭成,積木是排成一排搭好,每列有xi個積木,共n列。小明能夠對積木進行m次操作:
1.U L R yi : 將[L,R]列的積木高度全都改爲yi
2.Q L R : 查詢[L,R]列最長連續上升的列長度(LCIS)
知道[L,R]列最長連續上升的列長度過後,瑤瑤就可以開開心心地玩滑梯啦!
Ps:連續上升的列長度指對於一段合法區間,都有 。
話說積木是平的,瑤瑤是怎麼從高處滑到低處的呢??作爲姐姐也不知道,很想知道吧?你去問她吧。。
Input
第一行 兩個整數n,m;
第二行 n個整數,分別爲[1,n]區間每列積木個數;
接下來m行爲m個操作
Output
輸出x行,每行爲每次操作2的查詢結果。
Sample Input
5 4 2 1 2 3 1 Q 1 4 Q 2 5 U 2 4 3 Q 1 5
Sample Output
3 3 2
Hint
對於 100%的數據,有1 ≤ n ≤ 10^5 , 1 ≤ m ≤ 10^5 , 1 ≤ xi ≤ 10^8。
單組輸入,共10組數據。
Source
Manager
不知你是否相信 這是我兩年來做線段樹第一次使用LAZY標記,以前雖然早就聽說過LAZY標記對線段樹修改時的優化,但一直以爲太簡單而沒有去重視- -||| 這一次果斷自己寫了一個果然各種WA,不過最終結局是好的。
此題是一道經典維護線段樹+LAZY標記的使用,說真的這題線段樹題做的跟DP一樣,各種蛋疼。線段樹維護五個值,左右端點上的數值,左邊這個數取了之後的LIS(最長連續上升子序列)(記爲lv),右邊這個數取了之後的LIS(rv),以及整條線段的LIS(v),更新區間時的過程相當麻煩,我怕越講越煩就不贅述了,最好自己想通爲什麼要維護這五個值以及更新過程,或者看下面的代碼~~~。
稍微講一下LAZY標記的使用,當我們更新某段區間時,不可能把這段區間之下的所有子區間都更新,因爲那樣是n*n的複雜度,會超時,所以LAZY標記可以解決這一問題,更新大段時,大段先更新,並把lazy標記傳遞到它的兩個子段中,等用到那兩個子段時再更新,要用好LAZY標記尚需大量的實踐,因爲題目不是死的。
代碼:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<string>
#include<cstring>
#include<algorithm>
#include<fstream>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<iomanip>
#define rep(i,n) for(i=1;i<=n;i++)
#define MM(a,t) memset(a,t,sizeof(a))
#define INF 1e9
typedef long long ll;
#define mod 1000000007
using namespace std;
int n,m;
int a[100020];
struct aaa{
int l,r,v,lv,rv;
int lazy;
}xds[400020];
void update(int l,int r,int node,int num){
xds[node].lazy=-1;
if(l<r){
xds[node*2].lazy=num; xds[node*2+1].lazy=num;
}
xds[node].l=xds[node].r=num;
xds[node].v=xds[node].lv=xds[node].rv=1;
}
void pushup(int l,int r,int mid,int node){
int v=1;
if(l<r){
if(xds[node*2].lazy!=-1) update(l,mid,node*2,xds[node*2].lazy);
if(xds[node*2+1].lazy!=-1)update(mid+1,r,node*2+1,xds[node*2+1].lazy);
}
xds[node].l=xds[node*2].l; xds[node].r=xds[node*2+1].r;
xds[node].rv=xds[node*2+1].rv; xds[node].lv=xds[node*2].lv;
if(xds[node*2+1].l>xds[node*2].r){
v=max(v,xds[node*2].rv+xds[node*2+1].lv);
if(xds[node*2+1].v==r-mid) xds[node].rv=r-mid+xds[node*2].rv;
if(xds[node*2].v==mid-l+1) xds[node].lv=mid-l+1+xds[node*2+1].lv;
}
v=max(v,max(xds[node*2].v,xds[node*2+1].v));
xds[node].v=v;
if(v==(r-l+1)){
xds[node].lv=r-l+1;
xds[node].rv=r-l+1;
}
}
void build(int l,int r,int node){
xds[node].lazy=-1;
if(l==r){
xds[node].v=1;
xds[node].lv=1;
xds[node].rv=1;
xds[node].l=a[l];
xds[node].r=a[l];
}
else{
int mid=(l+r)/2;
build(l,mid,node*2); build(mid+1,r,node*2+1);
pushup(l,r,mid,node);
}
}
void change(int l,int r,int node,int x,int y,int num){
if(xds[node].lazy!=-1) update(l,r,node,xds[node].lazy);
if(l==x && r==y){
xds[node].lazy=num;
update(l,r,node,num);
}
else{
int mid=(l+r)/2;
if(x>=mid+1) change(mid+1,r,node*2+1,x,y,num);
else if(y<=mid) change(l,mid,node*2,x,y,num);
else{
change(l,mid,node*2,x,mid,num);
change(mid+1,r,node*2+1,mid+1,y,num);
}
pushup(l,r,mid,node);
}
}
aaa query(int l,int r,int node,int x,int y){
aaa res;
if(xds[node].lazy!=-1) update(l,r,node,xds[node].lazy);
if(x==l && y==r){
return xds[node];
}
else{
int mid=(l+r)/2;
if(x>=mid+1) return query(mid+1,r,node*2+1,x,y);
if(y<=mid) return query(l,mid,node*2,x,y);
aaa t1=query(l,mid,node*2,x,mid),t2=query(mid+1,r,node*2+1,mid+1,y);
int v=1;
res.l=t1.l; res.r=t2.r;
res.rv=t2.rv; res.lv=t1.lv;
if(t2.l>t1.r){
v=max(v,t1.rv+t2.lv);
if(t2.v==y-mid) res.rv=y-mid+t1.rv;
if(t1.v==mid-x+1) res.lv=mid-x+1+t2.lv;
}
v=max(v,max(t1.v,t2.v));
res.v=v;
if(v==(y-x+1)){
res.lv=y-x+1;
res.rv=y-x+1;
}
return res;
}
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
rep(i,n) scanf("%d",&a[i]);
build(1,n,1);
getchar();
rep(i,m){
int l,r,num;
char op[100];
scanf("%s",op);
if(op[0]=='Q'){
scanf("%d%d",&l,&r);
printf("%d\n",query(1,n,1,l,r).v);
}
else{
scanf("%d%d%d",&l,&r,&num);
change(1,n,1,l,r,num);
}
}
return 0;
}