hdu4973(线段树)

来源:互联网 发布:php 整数保留2位小数 编辑:程序博客网 时间:2024/06/06 03:25
题意:给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;}



0 0
原创粉丝点击