http://acm.hdu.edu.cn/showproblem.php?pid=4973
有两种操作
D l r 将【l,r】区间翻倍
Q l r询问[l,r]中相同数字出现的最多次数
比赛的时候脑子太乱了,没有想到怎么做。发现每次翻倍序列的长度都在变化,区间对应的数也在变,没有思路。
但是静下心来想一想,思路还是挺清晰的。
无论怎么翻倍,序列中的数都是连续的,范围是1~n。可以拿一个数组来记录每个数出现的次数,当更新或询问区间[l,r]时,可以利用其前缀和找到区间[l,r]对应的数字分别是lx,rx,对于lx+1,rx-1内的数字是完全翻倍的,可以用线段树维护区间的和相同数字的最大数目,由于l,r并不一定完全包含在lx.rx内,端点需要特殊处理。
那么重点就是怎样找到l,r对应的数更新区间[lx,rx],可以把每个数字所在区间的左端点作为连接l,r和lx,rx的纽带。这里想了许久才绕过来。
WA了几次,分别是:因为多次翻倍,输入的区间端点可能超int,要用__int64;push_dow的时候lazy标记要累加左右儿子,而不是直接赋值(经常犯nc的错误);query的时候忘记push_down(这个貌似更nc)
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 50010;
struct node
{
int l,r;
int lazy; //记录区间翻倍次数
LL sum;//区间的和
LL mx;//区间内相同数字出现的最多次数
}tree[maxn*4];
void push_up(int v)
{
tree[v].mx = max(tree[v*2].mx,tree[v*2+1].mx);
tree[v].sum = tree[v*2].sum + tree[v*2+1].sum;
return;
}
void push_down(int v)
{
if(tree[v].l == tree[v].r || tree[v].lazy == 0)
return;
tree[v*2].lazy += tree[v].lazy;//累加,累加
tree[v*2+1].lazy += tree[v].lazy;
tree[v*2].mx <<= (LL)tree[v].lazy;
tree[v*2].sum <<= (LL)tree[v].lazy;
tree[v*2+1].mx <<= (LL)tree[v].lazy;
tree[v*2+1].sum <<= (LL)tree[v].lazy;
tree[v].lazy = 0;
}
void build(int v, int l, int r)
{
tree[v].l = l;
tree[v].r = r;
tree[v].lazy = 0;
if(l == r)
{
tree[v].sum = (LL)1;
tree[v].mx = (LL)1;
return;
}
int mid = (l+r)>>1;
build(v*2,l,mid);
build(v*2+1,mid+1,r);
push_up(v);
}
void update(int v, LL st, LL l, LL r)//st是该节点的左端点在序列中的下标,那么可知这个节点所在区间是[st,st+tree[v].sum-1]。
{
if(st == l && st+tree[v].sum-1 == r)
{
tree[v].lazy++;
tree[v].mx <<= (LL)1;
tree[v].sum <<= (LL)1;
return;
}
if(tree[v].l == tree[v].r) //针对左右端点lx,rx,它们不全在区间[l,r]内,只更新其部分
{
tree[v].sum += (LL)(r-l+1);
tree[v].mx = tree[v].sum;
return;
}
push_down(v);
LL m = st + tree[v*2].sum - 1;
if(r <= m)
update(v*2,st,l,r);
else if(l > m)
{
update(v*2+1,m+1,l,r);
}
else
{
update(v*2,st,l,m);
update(v*2+1,m+1,m+1,r);
}
push_up(v);
}
LL query(int v, LL st, LL l, LL r)
{
if(st == l && st+tree[v].sum-1 == r)
return tree[v].mx;
if(tree[v].l == tree[v].r)
return r-l+1;
push_down(v);
LL m = st+tree[v*2].sum-1;
if(r <= m)
return query(v*2,st,l,r);
else if(l > m)
return query(v*2+1,m+1,l,r);
else return max(query(v*2,st,l,m),query(v*2+1,m+1,m+1,r));
}
int main()
{
int test;
int n,m;
LL l,r;
char ch[4];
scanf("%d",&test);
for(int item = 1; item <= test; item++)
{
scanf("%d %d",&n,&m);
build(1,1,n);
printf("Case #%d:\n",item);
while(m--)
{
scanf("%s %I64d %I64d",ch,&l,&r);
if(ch[0] == 'D')
update(1,1,l,r)
else
printf("%I64d\n",query(1,1,l,r));
}
}
return 0;
}