线段树系列(数据结构)

来源:互联网 发布:js仿京东商品详情 编辑:程序博客网 时间:2024/06/06 17:58

                                                                      线段树系列

第一类:单点更新,区间求和(线段树的基础)

A - 敌兵布阵

Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit

Status
Description
C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.

Input
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令

Output
对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。

Sample Input
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End

Sample Output
Case 1:
6
33

59


用了最基础的 建树 ,更新 ,求和。

<span style="font-size:18px;">#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<string>using namespace std;#define LL long long#define N 50010int v[N];struct tree{    int right,left,sum;}tr[N*4];void build(int id,int l,int r){    tr[id].left=l;    tr[id].right=r;    if(l==r)    {        tr[id].sum=v[l];    }    else    {        int m=(l+r)/2;        build(id*2,l,m);        build(id*2+1,m+1,r);        tr[id].sum=tr[id*2].sum+tr[id*2+1].sum;    }}void update(int id,int pos,int val){    if(tr[id].left==tr[id].right)        tr[id].sum+=val;    else    {        int mid=(tr[id].left+tr[id].right)/2;        if(pos<=mid) update(id*2,pos,val);        else         update(id*2+1,pos,val);        tr[id].sum=tr[id*2].sum+tr[id*2+1].sum;    }}int query(int id,int l,int r){    if(l<=tr[id].left&&tr[id].right<=r)    {        return tr[id].sum;    }    int m=(tr[id].left+tr[id].right)/2;    int ans=0;    if(l<=m) ans+=query(id*2,l,r);    if(m<r)  ans+=query(id*2+1,l,r);    return ans;}int main(){    int m,n,k;    while(~scanf("%d",&m))    {        k=1;        while(m--)        {            scanf("%d",&n);            for(int i=1;i<=n;i++)                scanf("%d",&v[i]);            build(1,1,n);            printf("Case %d:\n",k++);            char op[5];            int a,b;            while(1)            {                scanf("%s",op);                if(op[0]=='A')                {                    scanf("%d%d",&a,&b);                    update(1,a,b);                }                if(op[0]=='S')                {                    scanf("%d%d",&a,&b);                    update(1,a,-b);                }                if(op[0]=='Q')                {                    scanf("%d%d",&a,&b);                    printf("%d\n",query(1,a,b));                }                if(op[0]=='E')                        break;            }        }    }    return 0;}</span>



第二类:区间更新(1.区间增加或减少  2.区间直接赋值),区间求和。

解释:这类问题要用到lazy思想,即延迟。主要是push_down函数里面的变化,思想主要就是将更新记录在父亲节点下,需要使用的时候才把更新往下推,不需要的时候就保留在父亲节点那里,以此来减少时间。


B - Billboard
Time Limit:8000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit

Status
Description
在学校的入口处有一个巨大的矩形广告牌,高为h,宽为w。所有种类的广告都可以贴,比如ACM的广告啊,还有餐厅新出了哪些好吃的,等等。。

在9月1号这天,广告牌是空的,之后广告会被一条一条的依次贴上去。

每张广告都是高度为1宽度为wi的细长的矩形纸条。

贴广告的人总是会优先选择最上面的位置来帖,而且在所有最上面的可能位置中,他会选择最左面的位置,而且不能把已经贴好的广告盖住。

如果没有合适的位置了,那么这张广告就不会被贴了。

现在已知广告牌的尺寸和每张广告的尺寸,求每张广告被贴在的行编号。
Input
多组样例,不超过40个。

对每组样例,第一行包含3个整数h,w,n(1 <= h,w <= 10^9; 1 <= n <= 200,000) -广告牌的尺寸和广告的个数。

下面n行每行一个整数 wi (1 <= wi <= 10^9) - 第i张广告的宽度.
Output
对每张广告,输出它被贴在的行编号(是1到h之间的数),顶部是第一行。如果某广告不能被贴上,则输出-1。
Sample Input

3 5 5
2
4
3
3
3
Sample Output

1
2
1
3
-1


题意:找树中最左值大于或等于c值的点。

思路:首先确定最大值是否大于c,如果大于的话,就继续递归子树寻找,先左后右,后来找到最左边大于c的值。

题解:查询和更新在一起,找到最大值后, 最大值更新(减去相应的c值)。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<string>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int N=200010;int h,w,n;int MAX[N<<2];void push_up(int rt){    MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);}void build(int l,int r,int rt){    MAX[rt]=w;    if(l==r)    {        return ;    }    int m=(l+r)>>1;    build(lson);    build(rson);}int query(int c,int l,int r,int rt){    if(l==r)    {        MAX[rt]-=c;        return l;    }    int m=(l+r)>>1;    int ans=0;    if(MAX[rt<<1]>=c)        ans=query(c,lson);    else        ans=query(c,rson);    push_up(rt);    return ans;}int main(){    while(~scanf("%d%d%d",&h,&w,&n))    {        if(h>n)            h=n;        build(1,h,1);        while(n--)        {            int c;            scanf("%d",&c);            if(MAX[1]<c)                printf("-1\n");            else            {                printf("%d\n",query(c,1,h,1));            }        }    }    return 0;}

C - A Simple Problem with Integers
Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%I64d & %I64u
Submit

Status
Description
给出了一个序列,你需要处理如下两种询问。

"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。

"Q a b" 询问[a, b]区间中所有值的和。

Input
第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.

第二行包含n个整数,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。

接下来Q行询问,格式如题目描述。

Output
对于每一个Q开头的询问,你需要输出相应的答案,每个答案一行。

Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9
15


本题属于  区间增加和区间求和。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<string>using namespace std;#define LL long long#define maxn 100010LL v[maxn];int c;struct node{   LL sum,add;   int left,right;}tr[maxn*4];void build(int id,int l,int r){    tr[id].left=l,tr[id].right=r;    tr[id].add=0;    if(l==r)    {        tr[id].sum=v[l];    }    else    {        int mid=(l+r)/2;        build(id*2,l,mid);        build(id*2+1,mid+1,r);        tr[id].sum=tr[id*2].sum+tr[id*2+1].sum;    }}void push_down(int id){    if(tr[id].add)    {        int m=tr[id].right-tr[id].left+1;        tr[id*2].add+=tr[id].add;        tr[id*2+1].add+=tr[id].add;        tr[id*2].sum+=(m-m/2)*tr[id].add;        tr[id*2+1].sum+=(m/2)*tr[id].add;        tr[id].add=0;    }}void update(int id,int L,int R,int c){    if(L<=tr[id].left&&tr[id].right<=R)    {        tr[id].add+=c;        tr[id].sum+=(tr[id].right-tr[id].left+1)*c;    }    else    {        int mid=(tr[id].left+tr[id].right)/2;        push_down(id);        if(L<=mid)            update(id*2,L,R,c);        if(mid<R)            update(id*2+1,L,R,c);        tr[id].sum=tr[id*2].sum+tr[id*2+1].sum;    }}LL query(int id,int L,int R){    if(L<=tr[id].left&&tr[id].right<=R)        return tr[id].sum;    push_down(id);    int mid=(tr[id].left+tr[id].right)/2;    LL ans=0;    if(L<=mid)  ans+=query(id*2,L,R);    if(mid<R)   ans+=query(id*2+1,L,R);    return ans;}int main(){   int m,n;   char s[2];   int l,r;   while(~scanf("%d%d",&n,&m))   {       for(int i=1;i<=n;i++)        scanf("%lld",&v[i]);        build(1,1,n);       while(m--)       {           scanf("%s",s);           if(s[0]=='Q')           {               scanf("%d%d",&l,&r);               printf("%lld\n",query(1,l,r));           }           else           {               scanf("%d%d%d",&l,&r,&c);               update(1,l,r,c);           }       }   }   return 0;}


A - Just a Hook
Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit

Status
Description
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.




Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.

Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.

Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.

Sample Input
1
10
2
1 5 2
5 9 3

Sample Output
Case 1: The total value of the hook is 24.

题解:区间赋值,求总和。

#include<stdio.h>#include<iostream>#include<algorithm>using namespace std;#define LL long long#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int maxn = 100010;int col[maxn<<2];int sum[maxn<<2];void push_up(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void push_down(int rt,int m){    if(col[rt])    {        col[rt<<1]=col[rt];        col[rt<<1|1]=col[rt];        sum[rt<<1]=col[rt]*(m-(m>>1));        sum[rt<<1|1]=col[rt]*(m>>1);        col[rt]=0;    }}void build(int l,int r,int rt){    col[rt]=0;    if(l==r)    {        sum[rt]=1;    }    else    {        int m=(l+r)>>1;        build(l,m,rt*2);        build(m+1,r,rt*2+1);        push_up(rt);    }    //sum[rt]=r-l+1;}void update(int L,int R,int c,int l,int r,int rt){    if(L<=l&&r<=R)    {        col[rt]=c;        sum[rt]=(r-l+1)*c;        return ;    }     push_down(rt,r-l+1);    int m=(l+r)>>1;    if(L<=m) update(L,R,c,lson);    if(R>m)  update(L,R,c,rson);    push_up(rt);}/*LL query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R)    {        return sum[rt];    }    push_down(rt,r-l+1);    int m=(l+r)>>1;    int ans=0;    if(L<=m) ans+=query(L,R,lson);    if(m<R)  ans+=query(L,R,rson);    return ans;}*/int main(){    int k,n,cc,num;    scanf("%d",&k);    num=1;    while(k--)    {        scanf("%d",&n);        build(1,n,1);        scanf("%d",&cc);        while(cc--)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            update(a,b,c,1,n,1);        }        printf("Case %d: The total value of the hook is %d.\n",num++,sum[1]);    }    return 0;}


第三类:区间合并。

区间合并最重要的改变就是push_up函数,lsum,rsum,msum.  表示左边最长连续,右边最长连续,总共最长连续。
初始化,左边连续等于左儿子连续,右边连续等于右儿子连续;
void push_up(int rt,int m){    lsum[rt]=lsum[rt<<1];    rsum[rt]=rsum[rt<<1|1];    if(lsum[rt]==(m-(m>>1)))  lsum[rt]+=lsum[rt<<1|1];  //左儿子全都连续,左连续=左儿子+右左    if(rsum[rt] == m >> 1)    rsum[rt]+=rsum[rt<<1];  //右儿子全都连续,右连续=右儿子+左    msum[rt]=max(lsum[rt << 1|1]+rsum[rt<<1],max(msum[rt << 1],msum[rt<<1|1]));}   //最大的连续=max(右儿子左+左儿子右,max(左儿子最大,右儿子最大)


E - Hotel
Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit Status

Description

The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).

The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Dicontiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.

Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of roomsXi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.

Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and D(b) Three space-separated integers representing a check-out: 2, Xi, and Di

Output

* Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.

Sample Input

10 61 31 31 31 32 5 51 6

Sample Output

14705

题意:1,a  : 问酒店是否还有a个空房间,如果有的话,输出最左边的房间号,没有的话输出0。

           2,b,c  :酒店里[ b , b+c-1 ] 的客人退房,即房间全部清空。

思路:先找出空房间的最大数量,然后往下走,从左往右寻找,然后返回最左边的房间号。


<span style="font-size:18px;">#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<string>using namespace std;#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1const int N=50010;int rsum[N<<2],lsum[N<<2],msum[N<<2];int cov[N<<2];void push_up(int rt,int m){    lsum[rt]=lsum[rt<<1];    rsum[rt]=rsum[rt<<1|1];    if(lsum[rt]==(m-(m>>1)))      lsum[rt]+=lsum[rt<<1|1];    if(rsum[rt] == m >> 1)      rsum[rt]+=rsum[rt<<1];    msum[rt]=max(lsum[rt << 1|1]+rsum[rt<<1],max(msum[rt << 1],msum[rt<<1|1]));}void push_down(int rt,int m){    if(cov[rt]!=-1)    //有更新    {        cov[rt<<1]=cov[rt<<1|1]=cov[rt];          msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=cov[rt] ? 0:(m-(m>>1));  //根据改变条件,<span style="color: rgb(255, 102, 102);font-size:18px;">lsum,rsum,msum.到指定状态</span>        msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=cov[rt] ? 0:(m>>1);        cov[rt]=-1;   //传下去标记后,恢复    } }void build(int l,int r,int rt){    msum[rt]=lsum[rt]=rsum[rt]=r-l+1;   //初始长度,都为空    cov[rt]=-1;                         //初始标记    if(l==r)    {        return ;    }    int mid=(l+r)>>1;                   //递归更新    build(lson);    build(rson);}void update(int L,int R,int c,int l,int r,int rt){    if(L<=l&&r<=R)                    //找到范围,根据条件改变    {        msum[rt]=lsum[rt]=rsum[rt]=c ? 0:(r-l+1);        cov[rt]=c;        return ;    }    push_down(rt,r-l+1);             //未找到范围,继续往下走    int mid=(l+r)>>1;    if(L<=mid)  update(L,R,c,lson);   //左右儿子递归查找范围    if(mid<R)   update(L,R,c,rson);    push_up(rt,r-l+1);                //每步递归结束后,所更新的值都要往上走,更新。}int query(int w,int l,int r,int rt){    if(l==r)    {        return l;                 //查找到最左的那个数,返回最左值    }    push_down(rt,r-l+1);          //未查到的时候,继续往下走,查询并把延迟往下走    int mid=(l+r)>>1;             //查找的时候,从左往右,以免遗漏得出错误答案。    if(msum[rt<<1]>=w)  return query(w,lson);    else if(lsum[rt<<1|1]+rsum[rt<<1]>=w) return mid-rsum[rt<<1]+1;    else        return query(w,rson);}int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        build(1,n,1);        while(m--)        {            int a,b,c;            scanf("%d",&a);            if(a==1)            {                scanf("%d",&b);                if(msum[1]<b)                    printf("0\n");                else                {                    int k=query(b,1,n,1);        //查到最左的房间,并且住进去                    printf("%d\n",k);                    update(k,k+b-1,1,1,n,1);     //有人入住,则房间更新                }            }            else            {                scanf("%d%d",&b,&c);                update(b,b+c-1,0,1,n,1);      //有人离开,房间也要更新            }        }    }    return 0;}</span>



F - LCIS
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit Status

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]. 
 

Input

T in the first line, indicating the case number. 
Each case starts with two integers n , m(0<n,m<=10 5). 
The next line has n integers(0<=val<=10 5). 
The next m lines each has an operation: 
U A B(0<=A,n , 0<=B=10 5
OR 
Q A B(0<=A<=B< n). 
 

Output

For each Q, output the answer.
 

Sample Input

110 107 7 3 3 5 9 9 8 1 8 Q 6 6U 3 4Q 0 1Q 0 5Q 4 7Q 3 5Q 0 2Q 4 6U 6 10Q 0 9
 

Sample Output

11423125
 

    这同样是一道区间合并的题。

    题目大意:1.Q a b  求a ,b区间内的最长的递增序列的长度;

                      2.U a b  把 a 位置的数更新为b.

    注意:1.区间合并的条件,必须是a<b.

               2.区间不能合并的时候,也要记得根最大值更新为两儿子的最大值。

    

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<queue>#include<cstdlib>#include<string>using namespace std;#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define N 100010int rsum[N<<2],lsum[N<<2],msum[N<<2];int num[N];void push_up(int rt,int l,int r){    lsum[rt]=lsum[rt<<1];    rsum[rt]=rsum[rt<<1|1];    msum[rt]=max(msum[rt << 1],msum[rt<<1|1]); //先要返回最大值,然后再比较,注意!!!    int mid=(l+r)>>1;    int m=r-l+1;    if(num[mid]<num[mid+1])                    //注意区间合并的条件。    {        if(lsum[rt]==(m-(m>>1)))      lsum[rt]+=lsum[rt<<1|1];  //类似为Hotel        if(rsum[rt] == m >> 1)      rsum[rt]+=rsum[rt<<1];        msum[rt]=max(lsum[rt << 1|1]+rsum[rt<<1],msum[rt]);    }}void build(int l,int r,int rt){    if(l==r)    {        msum[rt]=lsum[rt]=rsum[rt]=1;           //初始长度都为1;        return ;    }    int mid=(l+r)>>1;    build(lson);    build(rson);    push_up(rt,l,r);                          //从最底层的叶子往上更新; }void update(int pos,int l,int r,int rt)        //单点更新,在主函数中已经更新了数值。 {    if(l==r)    {        return ;    }    int mid=(l+r)>>1;    if(pos<=mid)  update(pos,lson);    else   update(pos,rson);    push_up(rt,l,r);                           //维护的长度从叶子往上更新;       }int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R)        return msum[rt];    int mid=(l+r)>>1;    if(R<=mid)  return query(L,R,lson);//与一般的不同,需要一整段数都在同一边,比较出最大值。注意查找结果的性质。    if(L>mid)   return query(L,R,rson);    //如果能合并,则找出三者的最大值。max(a,b)只有两个参数    int ta,tb;    ta=query(L,R,lson);    tb=query(L,R,rson);    int res;    res=max(ta,tb);                       //先要返回最大值,然后再比较,注意!!!    if(num[mid]<num[mid+1])    {        int temp;        temp=min(rsum[rt<<1],mid-L+1)+min(lsum[rt<<1|1],R-mid);  //每段最大的增长序列与所要查找的范围的比较。        res=max(res,temp);    }    return res;}int main(){    int k,n,m;    char s[2];    scanf("%d",&k);   while(k--)   {       scanf("%d %d",&n,&m);       for(int i=1;i<=n;i++)         scanf("%d",&num[i]);       build(1,n,1);       while(m--)       {           int a,b;           scanf("%s",s);           if(s[0]=='Q')           {               scanf("%d %d",&a,&b);               a++;                                 //小技巧,题目数据从0开始,树是从1开始建立的。               b++;               printf("%d\n",query(a,b,1,n,1));           }           else           {               scanf("%d %d",&a,&b);               a++;               num[a]=b;               update(a,1,n,1);           }       }   }    return 0;}


0 0