可以直接用树状数组求和加二分判断l、r属于那一块,然后直接暴力即可,线段树也可做。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL __int64
using namespace std;
LL bit[200005];
LL a[50005];
int low(int a){return a&(-a);}
void merg(int a,int n,int p){
while(a<=n){
bit[a]+=p;
a+=low(a);
}
}
LL sum(int a){
LL s=0;
while(a>0){
s+=bit[a];
a=a-low(a);
}
return s;
}
int get(LL x,int n){
int le,ri,mid;
le=1;
ri=n;
while(le<=ri){
mid=(le+ri)/2;
if(sum(mid)<x) le=mid+1;
else ri=mid-1;
}
return le;
}
int max(int a,int b){
if(a<b) return b;
return a;
}
char cc[5],c;
int main()
{
int i,j,n,m,t,x1,x2,s,N;
LL p,k;
cin>>t;
N=t;
while(t--){
scanf("%d%d",&n,&m);
memset(bit,0,sizeof(bit));
for(i=1;i<=n;i++){
a[i]=1;
merg(i,n,1);
}
printf("Case #%d:\n",N-t);
for(i=0;i<m;i++){
scanf("%s",cc);
c=cc[0];
if(c=='Q'){
scanf("%I64d%I64d",&p,&k);
x1=get(p,n);
x2=get(k,n);
if(x1==x2){
printf("%d\n",k-p+1);
continue;
}
s=0;
for(j=x1+1;j<=x2-1;j++) s=max(s,a[j]);
s=max(s,sum(x1)-p+1);
s=max(s,k-sum(x2-1));
printf("%d\n",s);
}
else{
scanf("%I64d%I64d",&p,&k);
x1=get(p,n);
x2=get(k,n);
if(x1==x2){
merg(x1,n,k-p+1);
a[x1]+=k-p+1;
continue;
}
int w=sum(x1)-(p-1);
int q=k-sum(x2-1);
for(j=x1+1;j<=x2-1;j++){
merg(j,n,a[j]);
a[j]=a[j]<<1;
}
merg(x1,n,w);
a[x1]+=w;
merg(x2,n,q);
a[x2]+=q;
}
}
}
}