hdu 6315 Naive Operations (2018 Multi-University Training Contest 2 1007)

Naive Operations

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


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.
1n,q1000001lrn, 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
 
思路:
很明显的线段树,难点在于如何处理ai/bi的向下取整,我们可以对bi建一棵线段树,那么每次add(l,r)操作我们就可以抽象成(l,r)减一,如果区间【l,r】中有数字变为0,则表示b[i]这个数+1,再建一棵线段树储存每个区间+1的信息并将这个数变为原先的值继续循环就好了,querry(l,r),就直接在第二棵线段树上求区间值的和就可以了。
 
之前想到这个思路一直不敢写,感觉会超时,后面闻了一下学长,复杂度没问题就AC了 。
实现代码:
 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int inf = 0x3f3f3f3f;
const int M = 1e5+10;
double lazy[M<<2];
double b[M],num[M],sum[M<<2],minn[M<<2];
vector<int>v;
void pushup(int rt){
    minn[rt] = min(minn[rt<<1],minn[rt<<1|1]);
}

void pushdown(int rt){
     if(lazy[rt]){
        lazy[rt<<1] += lazy[rt];
        lazy[rt<<1|1] += lazy[rt];
        minn[rt<<1] -= lazy[rt];
        minn[rt<<1|1] -= lazy[rt];
        lazy[rt] = 0;
     }
}

void build(int l,int r,int rt){
    lazy[rt] = 0; minn[rt] = inf;
    if(l == r){
        minn[rt] = b[l];
        return ;
    }
    mid;
    build(lson);
    build(rson);
    pushup(rt);
}

void update(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        minn[rt] -= 1;
        lazy[rt] += 1;
        return ;
    }
    pushdown(rt);
    mid;
    if(L <= m) update(L,R,lson);
    if(R > m) update(L,R,rson);
    pushup(rt);
}

void update2(int p,int l,int r,int rt){
    if(l == r){
        minn[rt] = b[l];
        return ;
    }
    mid;
    pushdown(rt);
    if(p <= m) update2(p,lson);
    else update2(p,rson);
    pushup(rt);
}

int Query(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return minn[rt];
    }
    mid;
    pushdown(rt);
    int ret = inf;
    if(L <= m) ret = min(Query(L,R,lson),ret);
    if(R > m) ret = min(Query(L,R,rson),ret);
    return ret;
}

void query1(int l,int r,int rt){
    if(l == r){
        v.push_back(l);
        return ;
    }
    mid;
    pushdown(rt);
    pushdown(rt);
    if(minn[rt<<1] == 0) query1(lson);
    if(minn[rt<<1|1] == 0) query1(rson);
}

void pushup1(int rt){
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void build1(int l,int r,int rt){
    sum[rt] = 0;
    if(l == r){
        sum[rt] =  0;
        return ;
    }
    mid;
    build1(lson);
    build1(rson);
    pushup1(rt);
}

void update1(int p,int l,int r,int rt){
    if(l == r){
        sum[rt] += 1;
        return ;
    }
    mid;
    if(p <= m) update1(p,lson);
    else update1(p,rson);
    pushup1(rt);
}

int query(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return sum[rt];
    }
    mid;
    int ret = 0;
    if(L <= m) ret += query(L,R,lson);
    if(R > m) ret += query(L,R,rson);
    return ret;
}

int main()
{
    int n,q,x,l,r;
    char op[100];
    while(scanf("%d%d",&n,&q)!=EOF){
        for(int i = 1;i <= n;i ++){
            scanf("%d",&x);
            b[i] = x;
        }
        build(1,n,1);
        build1(1,n,1);
        while(q--){
            scanf("%s",op);
            if(op[0] == 'a'){
                //cout<<"update"<<endl;
                scanf("%d%d",&l,&r);
                update(l,r,1,n,1); //将第一棵树的l,r区间-1
                int cnt = Query(l,r,1,n,1);//求第一棵树的l,r区间的最小值
                //cout<<"cnt: "<<cnt<<endl;
                if(cnt == 0){  //如果区间最小值为0
                    query1(1,n,1);  //找到区间所有0的下表寸进vector里
                    for(int i = 0;i < v.size(); i++){ //遍历
                        //cout<<"v[i] :"<<v[i]<<endl;
                        update1(v[i],1,n,1); //在第二颗数记下更新值
                        update2(v[i],1,n,1); //将现在为0的数变成原来的值
                    }
                    v.clear();
                }
            }
            else {
                //cout<<"query"<<endl;
                 scanf("%d%d",&l,&r);
                 int ans = query(l,r,1,n,1);
                 printf("%d\n",ans);
            }
        }
    } 
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kls123/p/9367101.html