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): 887    Accepted Submission(s): 336


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
 
题意:给两个长度为N 数组 A和B,B是1-N的某一种排序,A全为0;
两种操作:
1.给你l,r 把数组A[l]到A[r]全部加1
2.给你l,r求A[l]/B[l]一直加到A[r]/B[r]的和;
 
思路:
数据量十万所以复杂度只能在NlogN到Nsqrt(N)左右;
而且很自然想到线段树操作;
区间加法 线段树的基本操作;
但是没办法每次除法都要处理到叶子节点;
所以如何处理除法是关键;
在比赛中想了无数办法,因为各种中途脑子短路和智商不行而打不出来(太蠢
✔正确做法 利用线段树维护区间最小值,每次区间加1时最小值减去1,当区间最小值减为0时说明这个区间中有叶子节点的A[X]/B[X]多了1;然后递归下去找到这个节点加1,跟他关联的区间的值都加上1;
所以复杂度每次区间加法和查询为logn寻找最小值减为0的叶子节点复杂度为logn 所以总复杂度为(NlogN*logN)
 
代码:
#include<bits/stdc++.h>

using namespace std;

#define ls (id<<1)
#define rs ((id<<1)|1)
#define mid ((l+r)>>1)
typedef long long LL;

const int maxn=100000+50;
int n,q;
int b[maxn];
struct Node{

    int mina;
    int valb;
    int zero_sum;
    int id;
    int lazy;

}node[maxn<<2];
void pushdown(int id,int l,int r){//往下更新
    node[ls].lazy+=node[id].lazy;
    node[rs].lazy+=node[id].lazy;
    node[ls].mina-=node[id].lazy;
    node[rs].mina-=node[id].lazy;
    node[id].lazy=0;
}
void pushup(int id,int l,int r){//往上更新
    node[id].zero_sum=node[ls].zero_sum+node[rs].zero_sum;
    node[id].mina=min(node[ls].mina,node[rs].mina);
}
void build(int l,int r,int id){
    node[id].zero_sum=node[id].lazy=0;
    if(l==r){

        node[id].valb=node[id].mina=b[l];
        //cout<<"id=="<<id<<" l=="<<l<<"  r=="<<r<<"node[id].mina="<<node[id].mina<<endl;
        return;
    }
    build(l,mid,ls);
    build(mid+1,r,rs);
    pushup(id,l,r);
}
void update(int l,int r,int id,int ql,int qr){
    //cout<<"id=="<<id<<" l=="<<l<<"  r=="<<r<<"node[id].mina="<<node[id].mina<<endl;
    if(l>r)return;
    if(node[id].mina>1&&ql<=l&&qr>=r){///到时候修改一下!!有包含的区间并且不存在要为0的叶子节点;
        node[id].lazy++;
        node[id].mina--;
        return;
    }
    if(l==r&&node[id].mina==1){//正好整除的叶子节点
        node[id].zero_sum++;
        node[id].lazy=0;
        node[id].mina=node[id].valb;
        return;
    }
    if(node[id].lazy)pushdown(id,l,r);
    if(qr<=mid)update(l,mid,ls,ql,qr);
    else if(ql>mid)update(mid+1,r,rs,ql,qr);
    else{
        update(l,mid,ls,ql,qr);
        update(mid+1,r,rs,ql,qr);
    }
    pushup(id,l,r);
}
int query(int l,int r,int id,int ql,int qr){
   // cout<<"id=="<<id<<" l=="<<l<<"  r=="<<r<<"node[id].mina="<<node[id].mina<<endl;
    if(l>r)return 0;
    if(ql<=l&&r<=qr)return node[id].zero_sum;//被需要查询包含的区间;
    /*if (node[id].mina <= 0) {
        update(1, 1, n, ql, qr);
    }*/
    if(qr<=mid)return query(l,mid,ls,ql,qr);
    else if(ql>mid)return query(mid+1,r,rs,ql,qr);
    else{
        return query(l,mid,ls,ql,qr)+query(mid+1,r,rs,ql,qr);
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    while(cin>>n>>q){
        for(int i=1;i<=n;i++)cin>>b[i];
        build(1,n,1);
        while(q--){
            char s[100];
            int ll,rr;
            cin>>s>>ll>>rr;
            if(s[0]=='a')update(1,n,1,ll,rr);
            else
                cout<<query(1,n,1,ll,rr)<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luowentao/p/9369326.html