题意:给1-n的数字,m次操作,每次操作将区间[l,r]中的数字翻倍,比如1,2,3,4,5,D 2,3,得到的结果是1,2,2,3,3,4,5, 求区间[l,r]中同一个数字出现的最多次数
解题思路:自己AC的一道线段树,感觉很不错。以[1,n]建立线段树,线段树中维护三个信息,max即当前区间内该区间内同一个数字出现的最多次数,sum即当前区间内数字的总个数,flag延迟标记。对于每次操作,找到对应的数字 和 出现的位置,然后进行更新和查询
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define LL __int64
#define N 50005
#define inf 0x7ffffff
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
struct node
{
int l,r,flag;
LL sum,max;
}tree[N<<2];
void PushUp(int o)
{
tree[o].sum = tree[2*o].sum + tree[2*o+1].sum;
tree[o].max = max(tree[2*o].max,tree[2*o+1].max);
}
void build(int o,int l,int r)
{
tree[o].l = l;
tree[o].r = r;
tree[o].flag = 0;
tree[o].max = 1;
if(l == r)
{
tree[o].sum = 1;
return;
}
int m = (l+r)/2;
build(2*o,l,m);
build(2*o+1,m+1,r);
PushUp(o);
}
void PushDown(int o)
{
if(tree[o].flag)
{
tree[2*o].flag += tree[o].flag;
tree[2*o+1].flag += tree[o].flag;
for(int i = 0; i < tree[o].flag; i++)//一开始因为这里wa了好多次
{
tree[2*o].max *= 2;
tree[2*o+1].max *= 2;
tree[2*o].sum *= 2;
tree[2*o+1].sum *= 2;
}
tree[o].flag = 0;
}
}
int find(int o,LL x,LL &k,LL &tmp)
{
if(tree[o].l == tree[o].r)
{
k = x;
tmp = tree[o].sum;
return tree[o].l;
}
PushDown(o);
if(x <= tree[2*o].sum) return find(2*o,x,k,tmp);
else return find(2*o+1,x-tree[2*o].sum,k,tmp);
}
void update1(int o,int pos,LL v)//单点更新
{
if(tree[o].l == tree[o].r)
{
tree[o].max += v;
tree[o].sum += v;
return;
}
PushDown(o);
int m = (tree[o].l + tree[o].r)/2;;
if(pos <= m) update1(2*o,pos,v);
else update1(2*o+1,pos,v);
PushUp(o);
}
void update2(int o,int x,int y)//区间更新
{
if(x <= tree[o].l && tree[o].r <= y)
{
PushDown(o);
tree[o].flag++;
tree[o].max *= 2;
tree[o].sum *= 2;
return;
}
PushDown(o);
int m = (tree[o].l+tree[o].r)/2;
if(x <= m) update2(2*o,x,y);
if(y > m) update2(2*o+1,x,y);
PushUp(o);
}
LL res;
void query(int o,int x,int y)
{
if(x <= tree[o].l && tree[o].r <= y)
{
if(res < tree[o].max) res = tree[o].max;
return;
}
PushDown(o);
int m = (tree[o].l + tree[o].r)/2;
if(x <= m) query(2*o,x,y);
if(y > m) query(2*o+1,x,y);
}
void output(int o)
{
cout<<tree[o].l<<" "<<tree[o].r<<" "<<tree[o].max<<" "<<tree[o].sum<<endl;
if(tree[o].l == tree[o].r)
return;
output(2*o);
output(2*o+1);
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int t,ca = 1;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
build(1,1,n);
printf("Case #%d:\n",ca++);
while(m--)
{
char str[2];
LL x,y;
LL lk,rk;
scanf("%s%I64d%I64d",str,&x,&y);
LL tmp;
int r = find(1,y,rk,tmp);//找数字r,出现的位置rk,该数字总的个数tmp
int l = find(1,x,lk,tmp);
//cout<<l<<" "<<lk<<" "<<tmp<<endl;
if(str[0] == 'D')
{
if(l == r) {
update1(1,l,rk-lk+1);
continue;
}
update1(1,r,rk);
update1(1,l,tmp-lk+1);
if(r - l > 1)
update2(1,l+1,r-1);
}
else
{
LL ans = 0;
if(l == r){
printf("%I64d\n",rk - lk + 1);
continue;
}
if(rk > ans) ans = rk;
if(tmp-lk+1 > ans) ans = tmp-lk+1;
if(r - l > 1){
res = 0;
query(1,l+1,r-1);
if(res > ans) ans = res;
}
printf("%I64d\n",ans);
}
//output(1);
}
}
return 0;
}