http://acm.hdu.edu.cn/showproblem.php?pid=4973
题意:给你一串连续升序数字和两种操作,D表示将[l, r]区间内的元素个数加倍,Q表示查询[l,r]区间内的最大元素个数。
ps:看的别人的博客。。草。。
思路:既然元素再怎么加倍也总是连续的,那么每个不同元素当做线段树子节点,开一个sum域表示同种元素的个数。于是难点就转化为了实际区间转化为线段树区间,只有找到线段树中的相对区间,才可以进行一系列加倍操作。我们这里传递一个st值,st代表查询更新区间的左节点,st+tree[i].sum-1代表查询更新区间的右节点,分别代表查询时的l与r。那么在线段树中递归时,tree[i]就代表递归到了线段树的第几层。传递时的中值就是mid = st-1+tree[i*2].sum,是按照大的更新区间方式传递,而非线段树区间。只要搞清这点就好办了,区间加倍就是找到对应区间直接对其总数与最值加倍,无需对端点特殊处理。这里我犯了个很SB的错,查询时push_down写成了push_up,问题是输入的样例还没问题,检查了我半天。。
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 1e8;
struct line
{
__int64 l, r;
__int64 sum;
__int64 maxx;
__int64 lazy;
}tree[8*N];
void push_up(__int64 i)
{
tree[i].maxx = max(tree[i*2].maxx, tree[i*2+1].maxx);
tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;
return;
}
void push_down(__int64 i)
{
if(tree[i].l == tree[i].r || tree[i].lazy == 0) return;
tree[i*2].lazy += tree[i].lazy;
tree[i*2+1].lazy += tree[i].lazy;
tree[i*2].maxx <<= tree[i].lazy;
tree[i*2].sum <<= tree[i].lazy;
tree[i*2+1].maxx <<= tree[i].lazy;
tree[i*2+1].sum <<= tree[i].lazy;
tree[i].lazy = 0;
}
void build(__int64 i, __int64 l, __int64 r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].lazy = 0;
if(l == r)
{
tree[i].sum = (__int64)1;
tree[i].maxx = (__int64)1;
return;
}
__int64 mid = (l+r) >> (__int64)1;
build(i*2, l, mid);
build(i*2+1, mid+1, r);
push_up(i);
}
void update(__int64 i, __int64 l, __int64 r, __int64 st)
{
if(st == l && st+tree[i].sum-1 == r)
{
tree[i].lazy++;
tree[i].maxx <<= (__int64)1;
tree[i].sum <<= (__int64)1;
return;
}
if(tree[i].l == tree[i].r)
{
tree[i].sum += (__int64)(r-(l-1));//这个一定要在前面
tree[i].maxx = tree[i].sum;
return;
}
push_down(i);
__int64 mid = st-1+tree[i*2].sum;
if(mid >= r)
update(i*2, l, r, st);
else if(mid < l)
update(i*2+1, l, r, mid+1);
else
{
update(i*2, l, mid, st);
update(i*2+1, mid+1, r, mid+1);
}
push_up(i);
}
__int64 query(__int64 i, __int64 l, __int64 r, __int64 st)
{
if(st == l && st-1+tree[i].sum == r)
{
return tree[i].maxx;
}
if(tree[i].l == tree[i].r)
{
return (__int64)(r-(l-1));
}
push_down(i);
__int64 mid = st-1+tree[i*2].sum;
if(mid >= r)
return query(i*2, l, r, st);
else if(mid < l)
return query(i*2+1, l, r, mid+1);
else
{
return max(query(i*2, l, mid, st),query(i*2+1, mid+1, r, mid+1));
}
}
int main()
{
// freopen("in.txt", "r", stdin);
__int64 t, n, m, l, r, Case = 1;
char s[5];
scanf("%I64d", &t);
while(t--)
{
scanf("%I64d%I64d", &n, &m);
build(1, 1, n);
printf("Case #%I64d:\n", Case++);
for(__int64 i = 1; i <= m; i++)
{
scanf("%s", s);
if(s[0] == 'D')
{
scanf("%I64d%I64d", &l, &r);
update(1, l, r, 1);
}
else if(s[0] == 'Q')
{
scanf("%I64d%I64d", &l, &r);
printf("%I64d\n", query(1, l, r, 1));
}
}
}
return 0;
}