hdu 4973 A simple simulation problem.(线段树)

来源:互联网 发布:大数据研究所 编辑:程序博客网 时间:2024/06/06 04:08

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;}


1 0