2013-04-12 17:41:01Morris

[NPSC][歸併樹] a656. E. 胖胖天天天胖


內容 :

胖胖天,天天胖!
 
身為一個專業飲料愛好者,胖胖天經常研究飲料相關的問題並樂此不疲。現在有許多飲料在胖胖天面前排成一排,每個飲料都有其購買的成本。他想從特定區段中挑出盡量多瓶飲料,使得總成本不超過他錢包裡的錢,請問他最多可以挑幾瓶呢?
 
聰明的胖胖天已經先寫了一個程式來輔助他喝遍天下的飲料,但謹慎的他還是請你也寫一份來確認他寫的程式是否正確。但為了肉眼比對方便,聰明的胖胖天決定比較結果的雜湊值就好,也就是假設對每次詢問所能購買的瓶數依序為p1, p2, ..., pk,則我們定義其雜湊值為(p1 + 1)^(p2 + 2)^...^(pk + k),其中^代表xor 運算。

輸入說明 :

輸入檔的第一行有一個正整數T (T<=514),表示接下來總共有幾筆測試資料。
 
每一筆測試資料第一行有兩個正整數N,Q (N,Q<=105),代表總共有N 瓶飲料,胖胖天將問你Q 個問題。飲料編號由左到右為1, 2, ...,N。下一行有N 個非負整數,依序代表每瓶飲料的購買成本,飲料的成本不會超過104。再接下來有Q 行,每行有三個整數L,R, S (1<=L<=R<=N, 0<=S<=109),代表胖胖天想問你如果他錢包裡剛好有S 元,他最多可以買幾瓶編號在L 到R 之間的飲料呢?

輸出說明 :

對於每筆測試資料,請輸出其對應的雜湊值。若對雜湊值之運算有所疑惑可以參考題目B 所附之程式碼。

範例輸入 :

2
3 1
5 1 4
1 3 5
5 2
1 1 5 1 5
2 5 5
1 4 5

範例輸出 :

3
6

提示 :

出處 :

NPSC 2012 高中組決賽 (管理:xavier13540)



题目简述:
在指定区间抓取总合不大于 S 的元素集合,而集合大小越大越好

题目分析:
对于区间[L,R]很明显地,从小排到大,依序挑入即可,照贪婪的思路。
但没办法对每个询问区间进行排序,因此使用归并树。
将合并排序的每个过程记录下来,然后二分边界数值。
小心,等价的边界数值要特别处理。

/*********************************************************/
/*  Problem: a656 "E. 胖胖天天天胖" from NPSC 2012 高中組決賽*/
/*  Language: CPP (3083 Bytes)                           */
/*  Result: AC(3.7s, 10.8MB) judge by this@ZeroJudge    */
/*  Author: morris1028 at 2013-04-12 09:00:55           */
/********************************************************/


#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
short ST[20][100010];
int AST[20][100010];
void build(int dep, int l, int r) {
    if(l < r) {
        int m = (l+r)/2, i;
        memcpy(ST[dep+1]+l, ST[dep]+l, (r-l+1)*2);
        build(dep+1, l, m);
        build(dep+1, m+1, r);
        int idx1 = l, idx2 = m+1, top = l, tmp = 0;
        while(idx1 <= m && idx2 <= r) {
            if(ST[dep+1][idx1] < ST[dep+1][idx2])
                ST[dep][top] = ST[dep+1][idx1++];
            else
                ST[dep][top] = ST[dep+1][idx2++];
            tmp += ST[dep][top];
            AST[dep][top++] = tmp;
        }
        while(idx1 <= m) {
            ST[dep][top] = ST[dep+1][idx1++];
            tmp += ST[dep][top];
            AST[dep][top++] = tmp;
        }
        while(idx2 <= r) {
            ST[dep][top] = ST[dep+1][idx2++];
            tmp += ST[dep][top];
            AST[dep][top++] = tmp;
        }
    }
    if(l == r)
        AST[dep][l] = ST[dep][l];
}
int L, R, S;
int key, Count, cost, same;
void query(int dep, int l, int r, int ql, int qr) {
    if(cost > S)   return ;
    if(l == ql && r == qr) {
        int ff = upper_bound(ST[dep]+l, ST[dep]+r+1, key)-(ST[dep]+l);
        int gg = lower_bound(ST[dep]+l, ST[dep]+r+1, key)-(ST[dep]+l);
        same += ff-gg;
        if(gg) {
            Count += gg;
            cost += AST[dep][gg+l-1];
        }
        return;
    }
    int m = (l+r)/2;
    if(m >= qr)
        query(dep+1, l, m, ql, qr);
    else if(m < ql)
        query(dep+1, m+1, r, ql, qr);
    else {
        query(dep+1, l, m, ql, m);
        query(dep+1, m+1, r, m+1, qr);
    }
}
inline int ReadInt(int *x) {
    static char c, neg;
    while((c = getchar()) < '-')    {if(c == EOF) return EOF;}
    neg = (c == '-') ? -1 : 1;
    *x = (neg == 1) ? c-'0' : 0;
    while((c = getchar()) >= '0')
        *x = (*x << 3) + (*x << 1) + c-'0';
    *x *= neg;
    return 1;
}
int main() {
    int t;
    int n, q, i, j;
    scanf("%d", &t);
    while(t--) {
        scanf("%d %d", &n, &q);
        for(i = 1; i <= n; i++) {
            //scanf("%d", &ST[0][i]);
            ReadInt(&j);
            ST[0][i] = j;
        }
        build(0, 1, n);
        int ans = 0;
        ST[0][0] = 0;
        for(i = 1; i <= q; i++) {
            //scanf("%d %d %d", &L, &R, &S);
            ReadInt(&L);
            ReadInt(&R);
            ReadInt(&S);
            int l = 0, r = n, m;
            int x = 0;
            while(l <= r) {
                m = (l+r)/2;
                key = ST[0][m], Count = 0, cost = 0, same = 0;
                query(0, 1, n, L, R);
                if(cost <= S) {
                    l = m+1;
                    if(key)
                        Count += min((S-cost)/key, same);
                    if(Count > x)   x = Count;
                } else
                    r = m-1;
            }
            ans ^= x+i;
        }
        printf("%d\n", ans);
    }
    return 0;
}