hdu6315—Naive Operations—多校暑假2—(线段树+lazy标记+思维)

Naive Operations

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Others)
Total Submission(s): 1935    Accepted Submission(s): 828

Problem Description

In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:
1. add l r: add one for al,al+1...ar
2. query l r: query ∑ri=lai/bi

 

 

Input

There are multiple test cases, please read till the end of input file.
For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries.
In the second line, n integers separated by spaces, representing permutation b.
In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation.
1≤n,q≤100000, 1≤lrn, there're no more than 5 test cases.

 

 

Output

Output the answer for each 'query', each one line.

 

 

Sample Input

 

5 12 1 5 2 4 3 add 1 4 query 1 4 add 2 5 query 2 5 add 3 5 query 1 5 add 2 4 query 1 4 add 2 5 query 2 5 add 2 2 query 1 5

 

 

Sample Output

 

1 1 2 4 4 6

 

 

Source

2018 Multi-University Training Contest 2

 

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6318 6317 6316 6315 6314 

 

 

这道题当时比赛的时候没有想法,然后赛后觉得这个想法还是很好的。

因为考虑到要求区间a[I]/B[I]的总和(向下取整),正常思路的话肯定会超时。想到之前做的一道题,就是维护最大值最小值判断是否需要更新。gorgeous sequence。  

这道题也类似是这样。有两种思路:

思路一:两个线段树,对a数组来说,需要维护区间最大值。对数组b来说,需要维护区间最小值。当最大值小于最小值时,没有增加。

思路二:一个线段树,每次add操作,相当于对b数组减1操作,当一段最小值为0时,说明某些叶子节点是需要ans加一的。这时就要向下递归到叶子节点。反之,用一个lazy标记一下就可以。这样复杂度要小。

思路二代码:

#include<bits/stdc++.h>
using namespace std;
#define lson id*2,l,(l+r)/2
#define rson id*2+1,(l+r)/2+1,r

const int maxn=100010;
int ans[maxn*4];
int minn[maxn*4];
int lazy[maxn*4];

int b[maxn];
int n;
void pushup(int id)
{
    minn[id]=min(minn[id*2],minn[id*2+1]);
    ans[id]=ans[id*2]+ans[id*2+1];
}
void pushdown(int id)
{
    if(lazy[id])
    {
        lazy[id*2]+=lazy[id];
        lazy[id*2+1]+=lazy[id];

        minn[id*2]-=lazy[id];
        minn[id*2+1]-=lazy[id];
        lazy[id]=0;
    }
}
void build(int id,int l,int r)
{
    ans[id]=0;
    lazy[id]=0;
    if(l==r)
    {
        scanf("%d",&b[l]);
        minn[id]=b[l];
        return ;
    }
    build(lson);
    build(rson);
    pushup(id);
}
//区间更新,需要注意当NIN减为0的时候,要ans++并且重新将b的值赋给MIN

void update(int id,int l,int r,int L,int R)
{
    if(L<=l &&R>=r)
    {
        minn[id]--;

        if(minn[id]==0)
        {
            if(l==r)
            {
                minn[id]=b[l];///这个时候对【rt】区间 最小值进行重新赋值
                ans[id]++;
                return;
            }
        }
        else
        {
             lazy[id]++;///这个时候不需要计数ans更新
             return ;///直到找到这个点,才能return。否则要继续找下去,一定要在括号内return
        }
    }
    pushdown(id);
    if(L<=(l+r)/2)
    {
        update(lson,L,R);
    }
    if(R>(l+r)/2)
    {
        update(rson,L,R);
    }
    pushup(id);
}

int query(int id,int l,int r,int L,int R)
{
    if(L<=l && R>=r)
        return ans[id];
    int sum=0;
    if(L<=(l+r)/2)
        sum+=query(lson,L,R);
    if(R>(l+r)/2)
        sum+=query(rson,L,R);
    return sum;
}
int main()
{
    char ch[30];
    int t;
    int X,Y;
    while(~scanf("%d%d",&n,&t))
    {
        build(1,1,n);
        for(int i=1;i<=t;i++)
        {
            scanf("%s%d%d",ch,&X,&Y);
            if(ch[0]=='q')
                printf("%d\n",query(1,1,n,X,Y));
            else
                update(1,1,n,X,Y);
        }
    }
    return 0;
}

代码二:(树状数组+线段树)

#include<bits/stdc++.h>
#define mod 1000000007
#define PI acos(-1)
#define ll long long
#define inf 999999
#define ull unsigned long long
using namespace std;

#define MAXN 100010
#define inf 0x3f3f3f3f
struct node{
    int l,r;//区间[l,r]
    int add;//区间的延时标记
    int mn; //区间最小值
}tree[MAXN<<2];//一定要开到4倍多的空间

int b[MAXN<<2];

int c[MAXN],n;
int lowbit(int i)
{
    return i&(-i);
}
void update(int i,int val)
{
    while(i<=n)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
int getsum(int i)
{
    int sum=0;
    while(i>0)
    {
        sum+=c[i];
        i-=lowbit(i);
    }
    return sum;
}
void pushup(int index)
{
    tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn);
}
/*
void pushdown(int index)
{
    if(tree[index].add)
    {
        tree[index<<1].mn += tree[index].add;
        tree[index<<1|1].mn += tree[index].add;
        tree[index<<1].add += tree[index].add;
        tree[index<<1|1].add += tree[index].add;
        tree[index].add = 0;
    }
}
*/
void build(int l,int r,int index)
{
    tree[index].l = l;
    tree[index].r = r;
    tree[index].add = 0;
    if(l == r)
    {
        scanf("%d",&b[index]);
        tree[index].mn=b[index];
        return ;
    }
    int mid = (l+r)>>1;
    build(l,mid,index<<1);
    build(mid+1,r,index<<1|1);
    pushup(index);
}
void solve(int index)
{
    if(tree[index].l==tree[index].r)
    {
        if(tree[index].mn==0)
        {
            tree[index].mn=b[index];
            update(tree[index].l,1);
        }
        return
    }
    pushdown(index);
    int mid=(tree[index].l+tree[index].r)>>1;
    if(tree[index*2].mn==0) ///最小值是0的话就要继续。
        solve(index*2);
    if(tree[index*2+1].mn==0)
        solve(index*2+1);
    pushup(index);
}
void updata(int l,int r,int index,int val)
{
    if(l <= tree[index].l &&  r>=tree[index].r)
    {
        tree[index].mn += val;
        tree[index].add += val;
        if(tree[index].mn==0)
        {
            solve(index);
        }
        return ;
    }
    pushdown(index);
    int mid = (tree[index].l+tree[index].r)>>1;
    if(l <= mid)
        updata(l,r,index<<1,val);
    if(r > mid)
        updata(l,r,index<<1|1,val);
    pushup(index);
}
int main()
{
    int q,l,r;
    char s[20];
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        memset(tree,0,sizeof(tree));
        build(1,n,1);
        while(q--)
        {
            scanf("%s%d%d",s,&l,&r);
            if(s[0]=='a')
            {
                updata(l,r,1,-1);
            }
            else
            {
                cout<<getsum(r)-getsum(l-1)<<endl;
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值