【2018 Multi-University Training Contest 2 1007】Naive Operations

【链接】 我是链接,点我呀:)
【题意】

给你两个数组a,b;
b数组是1..n的一个排列。
现在给你两种操作:
add l,r将a[l..r]都加上1
query l,r 询问$∑^r_l\frac{ai}{bi} $
其中a[i]/b[i]是下取整。
n<=10^5

【题解】

很优秀的题
我们可以在线段树1中维护所有a[i]/b[i]的值
想一下何时我们才要让线段树1中的值改变?
必然是我们一直加a的值,让a[i]的值超过了b[i]
设让线段树中的值改变操作为操作x
那么操作x最多湖执行多少次呢?
a最多变成10^5
那么就是
∑10^5/b[i] ,又b是一个排列
那么原式即\(10^5*(1/1+1/2+1/3+...+1/n)\)
其中右边那个式子是logn级别的。
那么总共要进行的操作x的次数就约等于nlogn
那么我们可以这么做。
另外开一个线段树2.
这个线段树一开始每个位置上的值为b[i]
我们可以维护一下区间最小值。
然后每次add(l,r)对应地把线段树2中相应位置递减1.
直到发现某个位置变成0了(最小值变成0就说明有些位置变成0了
那么就把线段树1中对应的a[i]/b[i]的值递增1.
然后再把那个位置重置为对应的b[i]就可以了。
根据上面的分析,这个递增操作次数最多n
logn次。
query操作直接就是线段树1的区间求和问题了。很轻松就能解决。

【代码】

#include <bits/stdc++.h>
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define rep1(i,a,b) for (int i = a;i<= b;i++)
using namespace std;

const double pi = acos(-1);
const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
const int N = 1e5;

int a[N+10],b[N+10],mi[N*4+10],tag[N*4+10],sum2[N*4+10];
int n,q;
char s[8];

void _updata2(int l,int r,int rt,int pos){
    if (l==r){
        sum2[rt]++;
        return;
    }
    int mid = (l+r)>>1;
    if (pos<=mid) _updata2(lson,pos);
    else _updata2(rson,pos);
    sum2[rt] = sum2[rt<<1]+sum2[rt<<1|1];
}

void push_down(int rt){
    if (tag[rt]>0){
        tag[rt<<1]+=tag[rt];tag[rt<<1|1]+=tag[rt];
        mi[rt<<1]-=tag[rt];mi[rt<<1|1]-=tag[rt];
        tag[rt] = 0;
    }
}

void _find0(int l,int r,int rt){
    if (l==r){
        _updata2(1,n,1,l);
        mi[rt] = b[l];
        return;
    }
    push_down(rt);
    int mid = (l+r)>>1;
    if (mi[rt<<1]==0) _find0(lson);
    if (mi[rt<<1|1]==0)_find0(rson);
    mi[rt]= min(mi[rt<<1],mi[rt<<1|1]);
}

void _updata1(int l,int r,int rt,int L,int R){
    if (L<=l && r<=R){
        mi[rt]--;
        tag[rt]++;
        if (mi[rt]==0){
            _find0(l,r,rt);
        }
        return;
    }
    push_down(rt);
    int mid = (l+r)>>1;
    if (L<=mid) _updata1(lson,L,R);
    if (mid<R) _updata1(rson,L,R);
    mi[rt] = min(mi[rt<<1],mi[rt<<1|1]);
}

long long get_ans2(int l,int r,int rt,int L,int R){
    if (L<=l && r <= R) return sum2[rt];
    int mid = (l+r)>>1;
    long long temp1 = 0,temp2 = 0;
    if (L<=mid) temp1 = get_ans2(lson,L,R);
    if (mid<R) temp2 = get_ans2(rson,L,R);
    return temp1+temp2;
}

void build1(int l,int r,int rt){
    tag[rt] = 0;
    int mid = (l+r)>>1;
    if (l==r){
        mi[rt] = b[l];
        return;
    }
    if (l<=mid) build1(lson);
    if (mid<r) build1(rson);
    mi[rt] = min(mi[rt<<1],mi[rt<<1|1]);
}

int main(){
    #ifdef LOCAL_DEFINE
        freopen("rush_in.txt", "r", stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    while (cin >> n >> q)
    {
        memset(a,0,sizeof a);
        memset(sum2,0,sizeof sum2);
        rep1(i,1,n) cin >> b[i];
        build1(1,n,1);
        while (q--)
        {
            int ll,rr;
            cin >> s >> ll >> rr;
            if (s[0]=='a')
                _updata1(1,n,1,ll,rr);
            else
                cout<<get_ans2(1,n,1,ll,rr)<<endl;

        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/AWCXV/p/9370165.html

时间: 2024-10-02 06:49:28

【2018 Multi-University Training Contest 2 1007】Naive Operations的相关文章

【2014 Multi-University Training Contest 3 1002】/【HDU 4888】 Redraw Beautiful Drawings

不容易啊,终于可以补第二个题了!! 顺便说一句:模版写残了就不要怪出题人啊 ~ (这残废模版研究了好长时间才找出错) 题目大意: 有一个n*m的矩阵,每一个格子里都将有一个数.给你每一行数字之和和每一列数字之和.求每一个位置能填0~k之间的哪个数.如果有多种可能输出"Not Unique",如果没有解输出"Impossible",如果一组解则将其输出. 解题思路: 最大流: 不可能的条件:是行之和和列之和不想等或者建图后的最大流与他们不想等. 多组的条件是:在最大流

2018 Multi-University Training Contest 3 1007 / hdu6325 Problem G. Interstellar Travel 凸包

Problem G. Interstellar Travel 题意: 给定平面上n个点,起点1 为(0,0),终点 n 为(Xn, 0),其它点的横坐标 0 <Xi<Xn,纵坐标 Xi >=0.每次可以飞到一个横坐标严格更大的点,代价为两个坐标的叉积.求起点到终点总代价最小的飞行路线,并输出字典序最小的路线.2≤n≤200000. Shortest judge solution: 979 bytes 题解: 显然坐标相同的点里只保留编号最小的点最优. 将起点到终点的路径补全为终点往下走到

2018 Nowcoder Multi-University Training Contest 2

Practice Link A. run 题意: 白云每次可以移动\(1\)米或者\(k\)米,询问移动的米数在\([L, R]\)范围内的方案数有多少. 思路: \(dp[i][2]\)表示到第\(i\)米,是通过\(1\)米的方式过来的还是\(k\)米的方式过来的,递推即可. 代码: #include <bits/stdc++.h> using namespace std; #define N 100010 const int p = 1e9 + 7; int f[N][2], g[N];

2018 Nowcoder Multi-University Training Contest 1

Practice Link J. Different Integers 题意: 给出\(n\)个数,每次询问\((l_i, r_i)\),表示\(a_1, \cdots, a_i, a_j, \cdots, a_n\)中有多少个不同的数. 思路: 先分别离线求出\(a_1, \cdots a_i\)以及\(a_j, \cdots, a_n\)中有多少个不同的数. 再考虑有多少个数既在\([1, i]\)中也在\([j, n]\)中,再离线做一次. 考虑一个数第一次出现的时候,那么这个数下一次出现

2018 Nowcoder Multi-University Training Contest 5

Practice Link A. gpa 题意: 有\(n\)门课程,每门课程的学分为\(s_i\),绩点为\(c_i\),要求最多删除\(k\)门课程,使得gpa最高. gpa计算方式如下: \[ \begin{eqnarray*} gpa = \frac{\sum s_ic_i}{\sum s_i} \end{eqnarray*} \] 思路: 首先删去的课程越多,gpa肯定不会变得更差. 所以我们肯定是删去\(k\)门课程. 考虑二分答案,check的时候要满足: \[ \begin{eq

【2018.08.19 C与C++基础】编程语言类型系统简介(草稿)

还是先占坑,等理顺了思路再写,学过的东西总是无法系统化,感觉什么都知道一点,但一深入却是一脸懵逼. 这真的是个问题,看似很努力,却无法成为一个master. 参考链接: 1. 编程语言的类型系统为何如此重要? https://www.zhihu.com/question/23434097 2. 程序语言中的类型系统怎么理解,它有哪些要素?如何由它演化出一门编程语言的? https://www.zhihu.com/question/22416404 3. 关于类型系统和类型推导的一些科普 http

【2018.10.11 C与C++基础】C Preprocessor的功能及缺陷(草稿)

一.前言及参考资料 C Preprocessor即所谓的C预处理器,C++也继承了C的预处理程序,但在C++语言的设计与演化一书中,C++的设计者Bjarne Strustrup提及他从未喜欢过C预处理器,认为C预处理器尤其是其中的宏定义存在许多缺陷,破坏了程序设计语言的类型系统及变量的作用域边界等等,但是语言设计者却很难为预处理中的各种功能找到具有更好结构而又高效的替代品. 我们知道在编译C/C++程序时,一般会经过预处理.编译.汇编.链接这四个阶段. 其中预处理在编译过程中发挥着不可替代作用

HDU 2018 Multi-University Training Contest 3 Problem A. Ascending Rating 【单调队列优化】

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6319 Problem A. Ascending Rating Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 5943    Accepted Submission(s): 2004 Problem Description Before

2018 Multi-University Training Contest 1 Distinct Values 【贪心 + set】

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6301 Distinct Values Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5312    Accepted Submission(s): 1823 Problem Description Chiaki has an array of