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;
}

猜你喜欢

转载自www.cnblogs.com/Basasuya/p/9236397.html