1. 程式人生 > >p3168 [CQOI2015]任務查詢系統(差分+主席樹)

p3168 [CQOI2015]任務查詢系統(差分+主席樹)

恕我才學淺薄,一開始想到的是樹狀陣列+線段樹,然後看了題解才第一次見到了差分這種神奇的科技
仔細想想,主席樹的本質不就是字首和嘛,加上一個差分也是可以的,沒想到真是罪過罪過
對時間維護一個差分
在Si處+Ki,在Ti+1處-Ki
用主席樹維護插入的數即可
不是很複雜就是程式碼寫了好長時間而且越debug越像題解

注意查前k大的時候比較這樣寫

    if(lch<kth)
        //向右
    else    
        //向左

不能這樣

    if(lch<=kth)
        //向右
    else    
        //向左

因為這樣在lch與kth相等的情況下,會一直向左走到還沒有開的節點上,導致RE
丟人的和題解極其相似的程式碼

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct PTNode{
    int lson, rson;
    long long sum, sz;
}x[100100*40];
struct Task{
    int Posi,Ki,changew;
    bool operator < (const Task &b) const {
        return Posi < b.Posi;
    }
}b[100100*3];
int a[100100], n, m, Nodecnt = 0, cnt = 0, root[100100];
void pushup(int o){
    x[o].sz = x[x[o].lson].sz + x[x[o].rson].sz;
    x[o].sum = x[x[o].lson].sum + x[x[o].rson].sum;
}
void insert(int l, int r, int &now, int pos, int c){
    x[++Nodecnt] = x[now];
    now = Nodecnt;
    x[now].sum += a[pos] *c ;
    x[now].sz += c;
    if(l == r)
        return;
    int mid=(l + r) >> 1;
    if(pos <= mid)
        insert(l, mid, x[now].lson, pos, c);
    else
        insert(mid + 1, r, x[now].rson, pos, c);
}
int query(int l, int r, int o, int kth){//前k小
    if(l==r)
        return x[o].sum/x[o].sz*kth;
    int mid=(l+r)>>1,lch=x[x[o].lson].sz;
    if(lch<kth)
        return query(mid+1,r,x[o].rson,kth-lch)+x[x[o].lson].sum;
    else
        return query(l,mid,x[o].lson,kth);
}
int main(){
    scanf("%d %d",&m ,&n);
    for(int i = 1; i <= m; i++){
        int x, y, z;
        scanf("%d %d %d",&x, &y, &z);
        b[++cnt] = (Task){x, z, 1};
        b[++cnt] = (Task){y+1, z, -1};
        a[i] = z;
    }
    sort(a + 1, a + m + 1);
    sort(b + 1, b + cnt + 1);
    int j = 1;
    for(int i = 1; i <= n; i++){
        root[i] = root[i-1];
        for(;j <= cnt && b[j].Posi == i;j++){
            int num = lower_bound(a + 1, a + n + 1 , b[j].Ki) - a;
            insert(1, n, root[i], num, b[j].changew);
        }    
    }
    long long preans = 1;
    for(int i = 1;i <= n;i++){
        long long xi,ki,a,b,c;
        scanf("%lld %lld %lld %lld", &xi, &a, &b, &c);
        ki = 1 + (a * preans + b) % c;
        if(ki<=x[root[xi]].sz)
            preans = query(1, n, root[xi], ki);
        else
            preans = x[root[xi]].sum;
        printf("%lld\n",preans);
    }
    return 0;
}