zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    POJ 1161 Walls ( Floyd && 建图 )
    POJ 1252 Euro Efficiency ( 完全背包变形 && 物品重量为负 )
    POJ 3111 K Best ( 二分 )
    2017乌鲁木齐网络赛 J题 Our Journey of Dalian Ends ( 最小费用最大流 )
    POJ 2112 Optimal Milking ( 经典最大流 && Floyd && 二分 )
    POJ 3281 Dining ( 最大流 && 建图 )
    POJ 2391 Ombrophobic Bovines ( 经典最大流 && Floyd && 二分 && 拆点建图)
    冲刺第一周第一天
    学习进度条12/3到12/9
    四则运算2
  • 原文地址:https://www.cnblogs.com/luowentao/p/9369326.html
Copyright © 2011-2022 走看看