标签:线段树 pre 存储 cin using long code 递增 初始
题意:
给定n个整数。 你有两种操作: U A B:用B替换第A个数。(编号从0开始) Q A B:输出[a,b]中最长连续严格递增子序列(LCIS)的长度。
第一行有一个整数T,表示数据组数。 每组数据以两个整数n,m(0 <n,m <= 100000)开始。 下一行有n个整数(0 <= val <= 100000)。
接下来的m行每行表示一个操作: U A B(0 <= A,n,0 <= B = 100000) 或 Q A B(0 <= A <= B <n)。
对于每个询问,输出答案。
思路:
结点修改以及区间查询,我们很容易想到线段树去实现。同时要求 LCIS 我们会想到线段树存储区间最大值的操作。但是关键在于区间如何去更新。
当左右两个子树区间向上合并的时候,父亲区间的最大值应该怎么更新。
进行分类讨论:
(1)合并时中间部分不会连接:左右区间合并时由于 左子树的右端值大于等于右子树的左端值,所以中间部分不能连接 (这样该区间最大值就等于 左右子树区间的最大值)
(2)如果要进行连接:{我们就需要记录某个区间的左右端连续长度,以及左右端点的值}
(i)判断是否更新 合并区间左右端连续长度,由于中间连接,所以如果左子树左端连续长度等于其区间长度,(即整个区间连续)则需要更新 合并区间左端长度 = 左子树左端连续长度+右子树左端连续长度
同理,合并区间右端长度 = 左子树右端连续长度+右子树右端连续长度
(ii) 最后再次判断是否更新区间最长
code: 其他具题见代码注解
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const double Pi = acos(-1.0); const double esp = 1e-9; const int inf = 0x3f3f3f3f; const int maxn = 5e5+7; const int maxm = 1e6+7; const int mod = 1e9+7; //区间合并问题 //要求得区间最长lcs,利用线段树及两两拆分 //合并后的最长长度为记录,左最长连续,右最长连续,和中间合并后的最长连续 int n,m; struct segmentTree { int arr[maxn]; //区间最大lcis int maxlen[maxn<<2]; //左右边界值 int ls[maxn<<2]; int rs[maxn<<2]; //左右最大lcis int lmax[maxn<<2]; int rmax[maxn<<2]; //结点从1开始到n int L[maxn<<2],R[maxn<<2]; void init(int n){ for(int i=1;i<=n;i++){ scanf("%d",&arr[i]); } } void build(int l,int r,int p){ L[p] = l; R[p] = r; if(l==r) { lmax[p] = rmax[p] = maxlen[p] = 1; ls[p] = rs[p] = arr[l]; return ; } int mid = (l+r)>>1; build(l,mid,p<<1); build(mid+1,r,p<<1|1); push_up(p); } void push_up(int p){ //对push_up()进行判断递推 //(1)左右端点、左右端连续长度赋值,初始区间最大值 ls[p] = ls[p<<1]; rs[p] = rs[p<<1|1]; lmax[p] = lmax[p<<1]; rmax[p] = rmax[p<<1|1]; maxlen[p] = max(maxlen[p<<1],maxlen[p<<1|1]); //(2)中间部分长度是否合并 if(rs[p<<1]<ls[p<<1|1]){ //(2*)判断是否更新该区间左右端连续最大长度 //(2**)如果左子树lcis等于其区间长度 if(lmax[p<<1] == (R[p<<1]-L[p<<1]+1)){ lmax[p] += lmax[p<<1|1]; } //(2**)如果右子树lcis等于其区间长度 if(rmax[p<<1|1] == (R[p<<1|1]-L[p<<1|1]+1)){ rmax[p] += rmax[p<<1]; } //(3)判断最大长度是否更新:左子树的右端与右子树的左端 maxlen[p] = max(maxlen[p],rmax[p<<1] + lmax[p<<1|1]); } } void update(int p,int k,int q){ if(L[p] == R[p]){ //更新结点值 ls[p] = rs[p] = k; return ; } int mid = (L[p]+R[p])>>1; if(q<=mid) update(p<<1,k,q); else update(p<<1|1,k,q); push_up(p); } int query(int ql,int qr,int p){ if(L[p]>=ql && R[p]<=qr){ return maxlen[p]; } int mid = (L[p]+R[p])>>1; int res = 0; if(ql<=mid) res = max(res,query(ql,qr,p<<1)); if(qr>mid) res = max(res,query(ql,qr,p<<1|1)); //(中间区间长度) if(rs[p<<1]<ls[p<<1|1]){ res = max(res,min(mid-ql+1,rmax[p<<1])+min(qr-mid,lmax[p<<1|1])); } return res; } }seg; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d %d",&n,&m); seg.init(n); seg.build(1,n,1); string s; for(int i=0;i<m;i++){ cin>>s; if(s[0]==‘Q‘){ int L,R; scanf("%d %d",&L,&R); printf("%lld\n",seg.query(L+1,R+1,1)); }else{ int ith,k; scanf("%d %d",&ith,&k); seg.update(1,k,ith+1); } } } return 0; }
标签:线段树 pre 存储 cin using long code 递增 初始
原文地址:https://www.cnblogs.com/Tianwell/p/11688519.html