线段树(3)之区间合并(基础题)

来源:互联网 发布:新闻类网站 数据库 编辑:程序博客网 时间:2024/06/15 18:03

      提一下,博主的英语四级过了微笑,就是这么6(虽然考了两回)

      区间合并:这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并,因为有可能合并之后连续最长区间比左右儿子的都长。大概就是这样。微笑上题:

总时间限制:
1000ms
内存限制:
65535kB
描述

有一个苦逼的种树人XX,需要种一排树,为什么说苦逼呢?因为总有一些熊孩子去把树苗拔掉(具体拔掉做什么,你们可以YY一下)。为了简化问题,把可以种树的位置编号为1-n。XX每次选择一个位置种树(如果已经有树了,则忽略),而熊孩子每次也选择一个位置拔树(如果没有树,则忽略)。现在XX想知道每次种树或者拔树后的连续有树的区间的最长长度。

输入
多组数据(大约10组)。对于每组数据:
第一行n,m;
接下来m行,每行q,a;
其中,q为1时表示XX种树,q为2时表示熊孩子拔树,a表示位置。
数据范围:1<=n,m<=10000,1<=q<=2,1<=a<=n。
输出
对于每组数据,输出m行,每次操作后的结果。
样例输入
4 51 11 31 42 41 2
样例输出
11213
提示
开始状态都没有种树

这道题比较简单,因为还没涉及延迟更新,只涉及最基本的点更新,贴代码:
#include<stdio.h>#define MAX 10000struct node{int l,r,mid;int lMax,rMax;  //分别是某个区间内左边界与右边界最长连续子区间长度int max;     //某个区间内最长连续子区间长度 };int Max(int a,int b){if(a>b)return a;else return b;}node t[MAX*4];int n;void BuildTree(int i,int l,int r){t[i].l=l;t[i].r=r;if(l==r){t[i].max=0;t[i].lMax=t[i].rMax=0;return;}t[i].mid=(l+r)/2;BuildTree(i*2,l,t[i].mid);BuildTree(i*2+1,t[i].mid+1,r);t[i].max=0;t[i].lMax=t[i].rMax=0;}void PushUp(int i)    //合并区间核心代码{t[i].max=Max(t[i*2].rMax+t[i*2+1].lMax,Max(t[i*2+1].max,t[i*2].max));if(t[i*2].r-t[i*2].l+1==t[i*2].max)t[i].lMax=t[i*2].max+t[i*2+1].lMax;else t[i].lMax=t[i*2].lMax;if(t[i*2+1].r-t[i*2+1].l+1==t[i*2+1].max)t[i].rMax=t[i*2+1].max+t[i*2].rMax;else t[i].rMax=t[i*2+1].rMax;}void Update(int i,int index,int num){if(t[i].l==t[i].r){if(t[i].max==0&&num==1)t[i].max=t[i].rMax=t[i].lMax=1;else if(t[i].max==1&&num==2)t[i].max=t[i].rMax=t[i].lMax=0;return;}if(index<=t[i].mid)Update(i*2,index,num);else Update(i*2+1,index,num);PushUp(i);}int main(){int m,i,q,a;while(scanf("%d%d",&n,&m)!=EOF){BuildTree(1,1,n);for(i=0;i<m;i++){scanf("%d%d",&q,&a);Update(1,a,q);printf("%d\n",t[1].max);}}return 0;}
好了,睡觉了,明天还有培训。再见

1 0