POJ2886 Who Gets the Most Candies? 线段树 反素数

题意:有一群小朋友围成一个环,编号1,2,3…N。每个人手上握着一个非0的数字,首先第K个人出列,然后看他手上的数字,假设为m,则从下一个开始第m个人出列,一直如此。并设i为小于等于N的最大反素数,问第i个出列的人得编号,i的约数个数。(设g(i)为i的约数的个数,若任意j<i,都有g(j)<g(i)则i为反素数)。

首先要得到[0,N]的最大反素数(怎么得到下面再说),然后模拟出列操作,用线段树来优化使得每次出列在O(logN)时间内完成。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

#define maxn 100005

int maxsub[maxn<<2], minsub[maxn<<2];
int lmax[maxn<<2], rmax[maxn<<2];
int lmin[maxn<<2], rmin[maxn<<2];
int sum[maxn<<2];

void PushUp(int rt) {
    int l = rt<<1;
    int r = l+1;
    sum[rt] = sum[l] + sum[r];
    maxsub[rt] = max(max(maxsub[l], maxsub[r]), rmax[l]+lmax[r]);
    minsub[rt] = min(min(minsub[l], minsub[r]), rmin[l]+lmin[r]);
    lmax[rt] = max(lmax[l], sum[l]+lmax[r]);
    rmax[rt] = max(rmax[r], sum[r]+rmax[l]);
    lmin[rt] = min(lmin[l], sum[l]+lmin[r]);
    rmin[rt] = min(rmin[r], sum[r]+rmin[l]);
}

void build(int l, int r, int rt) {
    if (l == r) {
       scanf("%d", &sum[rt]);
       minsub[rt] = lmax[rt] = rmax[rt] = lmin[rt] = rmin[rt] = maxsub[rt] = sum[rt];
       return;
    }
    int m = (l+r)>>1;
    build(l, m, rt<<1);
    build(m+1, r, rt<<1|1);
    PushUp(rt);
}

void update(int target, int val, int l, int r, int rt) {
    if (l == r) {
        sum[rt] = maxsub[rt] = minsub[rt] = val;
        lmax[rt] = rmax[rt] = lmin[rt] = rmin[rt] = val;
        return;
    }
    int m = (l+r)>>1;
    if (m >= target) update(target, val, l, m, rt<<1);
    else update(target, val, m+1, r, rt<<1|1);
    PushUp(rt);
}

int main()
{
    int n, m, ans;

    scanf ("%d", &n);
    build(1, n, 1);
    scanf("%d", &m);
    while (m--) {
        int a, b;
        scanf ("%d%d", &a, &b);
        update(a, b, 1, n, 1);
        if (sum[1] == maxsub[1]) //序列全为非负数的时候
            ans = sum[1] - minsub[1];
        else ans = max(maxsub[1], sum[1]-minsub[1]);
        printf ("%d\n", ans);
    }
    return 0;
}

 

posted @ 2013-07-25 17:17  某某。  阅读(201)  评论(0编辑  收藏  举报