同4027挺像的,只不过一个翻倍一个开方。
维护一颗线段树,记录两个值,分别是当前区间细胞总个数和当前区间同类细胞最多的个数,以每类细胞为一个节点,更新时更新每类细胞的数量即可,注意左右边界的判定,因为两边可能不完全翻倍,只有部分细胞翻倍,注意longlong,其他没什么了。
这类题目最大的特点便是值的变化特别快,因此一个点不可能翻倍很多次,1翻个几十倍就要超int了,因此完全没必要延迟更新什么的,直接按照单点更新来即可,没延迟更新400多ms过的。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
#define LL long long int
using namespace std;
const int MAX=50050;
LL sum[MAX<<2];
int mm[MAX<<2];
int n,m;
int max(int a,int b)
{
return a>b?a:b;
}
void pushup(int rt)
{
mm[rt]=max(mm[rt<<1],mm[rt<<1|1]);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if (l==r)
{
sum[rt]=mm[rt]=1;
return ;
}
delf;
build(lson);
build(rson);
pushup(rt);
return ;
}
void update(LL L,LL R,int l,int r,int rt)
{
if (l==r)
{
sum[rt]+=(R-L+1);
mm[rt]=sum[rt];
return ;
}
delf;
LL s=sum[rt<<1];
if (s>=L)
{
if (sum[rt<<1]<=R)
update(L,sum[rt<<1],lson);
else
update(L,R,lson);
}
if (R>s)
{
if (L>s)
update(L-s,R-s,rson);
else
update(1,R-s,rson);
}
pushup(rt);
return ;
}
LL query(LL L,LL R,int l,int r,int rt)
{
if (L==1&&sum[rt]<=R)
return mm[rt];
if (l==r)
return (R-L+1);
delf;
LL ans=0;
if (sum[rt<<1]>=L)
{
if (sum[rt<<1]<=R)
ans=max(ans,query(L,sum[rt<<1],lson));
else
ans=max(ans,query(L,R,lson));
}
if (R>sum[rt<<1])
{
if (L>sum[rt<<1])
ans=max(ans,query(L-sum[rt<<1],R-sum[rt<<1],rson));
else
ans=max(ans,query(1,R-sum[rt<<1],rson));
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
for (int c=1;c<=T;c++)
{
cin>>n>>m;
build(1,n,1);
printf("Case #%d:\n",c);
while(m--)
{
char p;
int l,r;
getchar();
scanf("%c%d%d",&p,&l,&r);
if (p=='D')
update(l,r,1,n,1);
else
printf("%I64d\n",query(l,r,1,n,1));
}
}
}