Codeforces Round #489 (Div. 2) E. Nastya and King-Shamans

这道题的算法是:

i从1开始,首先求sum(1-i),然后在[i+1, n]中找到第一个a[j]>=sum(1, i)

如果a[j]==sum(1, i)结束搜索,否则令i=j,循环过程

因为每次做完一次之后sum会至少增大一倍,所以一个查询的复杂度会维持到log(Max(a[i]))

需要维护 区间最大值和区间和 的线段树来实现算法

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 2e5+5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1

int n, q;
int A[N];
int maxx[N << 2];
ll sum[N << 2];
void Build(int l, int r, int rt) {
    if(l == r) {
        sum[rt] = A[l];
        maxx[rt] = A[l];
        return;
    }
    int m = (l + r) >> 1;
    Build(lson);
    Build(rson);
    sum[rt] = sum[rt << 1] + sum[rt << 1|1];
    maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);
}
void Update(int pos, int num, int l, int r, int rt) {
    if(l == r) {
        sum[rt] = num;
        maxx[rt] = num;
        return;
    }
    int m = (l + r) >> 1;
    if(pos <= m) Update(pos, num, lson);
    else Update(pos, num, rson);
    sum[rt] = sum[rt << 1] + sum[rt << 1|1];
    maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);
}
ll Sum(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return sum[rt];
    }
    int m = (l + r) >> 1;
    ll ret = 0;
    if(L <= m) ret += Sum(L, R, lson);
    if(R > m) ret += Sum(L, R, rson);
    return ret;
}

pair<ll, int> Ans;
void Find(int L, int R, ll num, int l, int r, int rt) {
    if(l == r) {
        Ans = make_pair(maxx[rt], l);
        return;
    }
    int m = (l + r) >> 1;
    if(maxx[rt << 1] >= num && L <= m) Find(L, R, num, lson);
    if(maxx[rt<<1|1] >= num && R > m && Ans.first == -1) Find(L, R, num, rson);
}
int main() {
    while(~scanf("%d %d", &n, &q)) {
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &A[i]);
        }
        Build(1 , n, 1);
    //  printf("%lld\n", Sum(1, 2, 1, n, 1));
        for(int i = 0; i < q; ++i) {
            int a, b; scanf("%d %d", &a, &b);
            Update(a, b, 1, n, 1);
            A[a] = b;
            if(A[1] == 0) printf("1\n");
            else if(A[1] == A[2]) printf("2\n");
            else {
                int pre = 2;
                while(1) {
                    ll tmpTarget = Sum(1, pre, 1, n, 1);
                    if(tmpTarget > maxx[1]) {
                        printf("-1\n");
                        break;
                    }
                    Ans = make_pair(-1, -1);
                    Find(pre+1, n, tmpTarget, 1, n, 1);
                    if(Ans.first == -1) {
                        printf("-1\n");
                        break;
                    }
                    ll nowTarget = Sum(1, Ans.second-1, 1, n, 1);
                    if(Ans.first == nowTarget) {
                        printf("%d\n", Ans.second);
                        break;
                    } else {
                        pre = Ans.second;
                    }

                }
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Basasuya/p/9236397.html

时间: 2024-08-30 17:48:46

Codeforces Round #489 (Div. 2) E. Nastya and King-Shamans的相关文章

Codeforces Round #489 (Div. 2)

Codeforces Round #489 (Div. 2) A. Nastya and an Array #include <bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;++i) #define frep(i,a,b) for(int i=a;i>=b;--i) #define mem(W) memset(W,0,sizeof(W)) #define pb push_back typedef long long ll; c

Codeforces Round #546 (Div. 2) C. Nastya Is Transposing Matrices

C. Nastya Is Transposing Matrices time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Nastya came to her informatics lesson, and her teacher who is, by the way, a little bit famous here gave he

Codeforces Round #546 (Div. 2) D. Nastya Is Buying Lunch

题意: 长度为n的数组{pi},m对关系(a,b),如果a正好在数组中位于b的前一个位置,则可以交换a和b,问最多可以让pn的位置往前移动多少 题解: 如果pn可以往前走k步,他肯定可以和pk交换.如果pk后面的数都可与他交换,则最后可以使pn和pk互换,使pn移动到pk的位置 #include <bits/stdc++.h> //#pragma comment(linker, ”/STACK:36777216“) using namespace std; typedef long long

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除