hdu 6315--线段树的基本操作

题意:

给你n个数,q个询问,这n个数b[i]是不变的,还有n个数a[i]初始值为0,询问有两种,一种是在(l,r)的区间内,ai加1,另一种查询(l,r)内a[i]/b[i]的值。

思路:

比赛的时候并没有什么思路,因为我们队对线段树不太熟悉,赛后看了大佬的博客才知道原来可以用线段树维护三个值,一个是a[i]的区间最大值maxa,一个是b[i]的区间最小值minb,一个是答案cnt。当a[i]的区间最大值大于b[i]的区间最小值,我们就需要找到那个位置,并把那个位置上的cnt++,minb+=b[i]。知道思路后就是一个很裸的线段树了。

至于怎么找到那个引起a[i]的区间最大值大于b[i]的区间最小值的位置,有人说要二分找那个位置,其实不需要的,我们可以在区间更新的时候,直接判断是否是这个位置的maxa>minb,如果是直接更新。因为区间更新肯定可以遍历所有区间内的位置,所以不可能会漏掉。

代码:

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<functional>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
using namespace std;
#define MAXN 100010
struct node {
    int l, r;//区间端点
    int  add;//延迟标记
    int maxa,minb,cnt;
}tree[MAXN * 4];//必须乘以4
int b[MAXN];
void push_up(int rt)
{
    tree[rt].minb=min(tree[rt<<1].minb,tree[rt<<1|1].minb);
    tree[rt].cnt=tree[rt<<1].cnt+tree[rt<<1|1].cnt;
    tree[rt].maxa=max(tree[rt<<1].maxa,tree[rt<<1|1].maxa);
}
void build(int p, int l, int r)//调用时build(1,l,r);
{
    tree[p].add=0;
    tree[p].l = l, tree[p].r = r;
    if (l == r){
        tree[p].cnt=tree[p].maxa=0;
        tree[p].minb=b[l];
        return;
    }
    int mid = (l + r) >>1;
    build(p <<1, l, mid);
    build(p <<1|1, mid + 1, r);
    push_up(p);
}
void spread(int p){
    if (tree[p].add){
        int v=tree[p].add;
        tree[p].add = 0;//记得清零
        tree[p<<1].maxa+=v;
        tree[p<<1|1].maxa+=v;
        tree[p<<1].add+=v;
        tree[p<<1|1].add+=v;
    }
}

void change(int p, int l, int r, int d)//区间更新,调用时change(1,l,r,d)
{
    if (l <= tree[p].l&&r >= tree[p].r)//若当前节点的区间在l,r内部
    {
        tree[p].maxa++;
        if(tree[p].maxa<tree[p].minb)
        {
            tree[p].add++;
            return ;
        }
        if(tree[p].l==tree[p].r&&tree[p].maxa>=tree[p].minb)//这个位置被找到了
        {
            tree[p].cnt++;
            tree[p].minb+=b[tree[p].l];
            return ;
        }
    }
    spread(p);//向下一层拓展延迟标记
    int mid = (tree[p].l + tree[p].r) / 2;
    if (l <= mid)change(p <<1, l, r, d);
    if (r > mid)change(p <<1|1, l, r, d);
    push_up(p);
}

int ask(int p, int l, int r)//调用ask(1,l,r)
{
    if (l <= tree[p].l&&r >= tree[p].r)
        return tree[p].cnt;
    spread(p);//向下一层拓展延迟标记
    int mid = (tree[p].l + tree[p].r) >>1;
    int ans=0;
    if (l <= mid)ans+= ask(p <<1, l, r);
    if (r > mid) ans+= ask(p <<1|1, l, r);
    return ans;
}

int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF){
    for(int i=1;i<=n;i++)
        scanf("%d",&b[i]);
    build(1,1,n);
    while(q--)
    {
       char a[10];
       scanf("%s",a);
       int l,r;
       scanf("%d%d",&l,&r);
       if(a[0]=='a')
        change(1,l,r,1);
       else if(a[0]=='q')
       {
           int ans=ask(1,l,r);
           printf("%d\n",ans);
       }
    }
  }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dhydye/article/details/81270945
今日推荐