这道题是CD老OJ上面的一道题,现在在新OJ上的题号是360,开始在VJ上做的提交一直RE(囧)。后来才知道OJ移位了。
这道题是一个简单的成段更新+区间合并的线段树的题,1A还让我小激动了一下
这道题的大概意思是有两种操作,一种是成段地增加一个值,另外一种是询问从l到r这段区间内的最长递增子序列
首先先分析一下,如果某一段的值成段地增加一个量,那么该区间内的数的相对大小是不变的,因此递增子序列的长度是不会改变的
是要分析对于结果有影响的信息与值:一是每个子区间中的最值,二是有可能在两个区间合并之后的两个区间的中间的两段成为新的最值,因此我们需要判断中间的两个值是否可以合并,从何得知:我们需要在运算过程中分别记录下左端点的值和右端点的值,来判断是否可以合并。因此在每个节点增设两个值lv,rv。
还有一个问题就是在查询过程中,可能会存在查询的范围R-mid比lsum[rt<<1|1]小(mid-L+1比rsum[rt<<1]小),因此用比较取较小值相加就OK;额
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int SIZEN=100005; 6 int sum[SIZEN<<2],lsum[SIZEN<<2],rsum[SIZEN<<2]; 7 int lv[SIZEN<<2],rv[SIZEN<<2],add[SIZEN<<2]; 8 int a[SIZEN]; 9 void pushup(int len,int rt){ 10 int tmp; 11 lsum[rt]=lsum[rt<<1]; 12 rsum[rt]=rsum[rt<<1|1]; 13 lv[rt]=lv[rt<<1];rv[rt]=rv[rt<<1|1]; 14 if(lsum[rt]==(len-(len>>1))&&rv[rt<<1]<lv[rt<<1|1]) lsum[rt]+=lsum[rt<<1|1]; 15 if(rsum[rt]==(len>>1)&&rv[rt<<1]<lv[rt<<1|1]) rsum[rt]+=rsum[rt<<1]; 16 tmp=rsum[rt<<1]+lsum[rt<<1|1]; 17 if(rv[rt<<1]<lv[rt<<1|1]) 18 sum[rt]=max(tmp,max(sum[rt<<1],sum[rt<<1|1])); 19 else sum[rt]=max(sum[rt<<1],sum[rt<<1|1]); 20 } 21 void pushdown(int rt){ 22 if(add[rt]!=0){ 23 add[rt<<1]+=add[rt]; 24 add[rt<<1|1]+=add[rt]; 25 lv[rt<<1]+=add[rt];rv[rt<<1]+=add[rt]; 26 lv[rt<<1|1]+=add[rt];rv[rt<<1|1]+=add[rt]; 27 add[rt]=0; 28 } 29 } 30 void update(int L,int R,int o,int l,int r,int rt){ 31 if(L<=l&&r<=R){ 32 add[rt]+=o; 33 lv[rt]+=o;rv[rt]+=o; 34 return; 35 } 36 pushdown(rt); 37 int mid=(l+r)>>1; 38 if(L<=mid) update(L,R,o,l,mid,rt<<1); 39 if(mid+1<=R) update(L,R,o,mid+1,r,rt<<1|1); 40 pushup(r-l+1,rt); 41 } 42 void build(int l,int r,int rt){ 43 add[rt]=0; 44 if(l==r){ 45 sum[rt]=lsum[rt]=rsum[rt]=1; 46 lv[rt]=rv[rt]=a[l]; 47 return; 48 } 49 int mid=(l+r)>>1; 50 build(l,mid,rt<<1); 51 build(mid+1,r,rt<<1|1); 52 pushup(r-l+1,rt); 53 } 54 int query(int L,int R,int l,int r,int rt){ 55 if(L<=l&&r<=R){ 56 return sum[rt]; 57 } 58 int mid=(l+r)>>1,r1,r2,r3; 59 int len=r-l+1; 60 r1=r2=r3=-1; 61 pushdown(rt); 62 if(L<=mid) r1=query(L,R,l,mid,rt<<1); 63 if(mid+1<=R) r2=query(L,R,mid+1,r,rt<<1|1); 64 if(rv[rt<<1]<lv[rt<<1|1]) r3=min(rsum[rt<<1],mid-L+1)+min(lsum[rt<<1|1],R-mid); 65 return max(r1,max(r2,r3)); 66 } 67 int main() 68 { 69 //freopen("data.in","r",stdin); 70 int i,j,_; 71 char c; 72 int l,r,o; 73 int n,q,txt=1; 74 scanf("%d",&_); 75 while(_--){ 76 printf("Case #%d: ",txt++); 77 scanf("%d%d",&n,&q); 78 for(i=1;i<=n;i++) 79 scanf("%d",&a[i]); 80 build(1,n,1); 81 while(q--){ 82 scanf(" %c",&c); 83 if(c=='a'){ 84 scanf("%d%d%d",&l,&r,&o); 85 update(l,r,o,1,n,1); 86 } 87 else{ 88 scanf("%d%d",&l,&r); 89 int ret=query(l,r,1,n,1); 90 printf("%d ",ret); 91 } 92 } 93 } 94 return 0; 95 }