P3168 [CQOI2015]任务查询系统

P3168 [CQOI2015]任务查询系统


题意

给出若干带有权值的区间, 每个区间可能相交或相离, 每个区间有三个属性(Si, Ei, Pi), 分别表示左端点,右端点,权值,其中端点范围属于[1, N]内;
随后有N条询问, 给出Xi, Ki, 令涉及到[1, Xi]区间中排名第Ki小的区间为A, 输出排名属于[1, K]时间点小于等于A的所有区间的权值和


Solution

  • 将区间中权值的添加与删去用差分操作来表示
  • 离散化端点, 权值
  • 按时间线排序的差分操作建立主席树
  • 于每条询问, 输出查询结果即可

需要注意的点

  1. 主席树的空间为 logNNlogN * N(最好多开1倍…)
  2. 注意离散化数值与权值之间不要混用

Code

#include<bits/stdc++.h>
#define reg register

const int maxn = 2e5 + 10;

int M;
int N;
int Len;
int cnt;
int Q_num;
int node_cnt;
int B[maxn<<2];
int rot[maxn*10];
int Apos[maxn<<2];

struct Cf{ int pos, val, opt; } A[maxn<<2];

struct Task{ int S, E, P; } ts[maxn<<2];

struct Node{ int lt, rt, val_sum, sum, cnt; } T[maxn*18]; 

bool cmp(Cf a, Cf b){ return a.pos < b.pos; }

void Add_node(int &now, int last, int l, int r, int val, int opt, int v){
        T[now = ++ node_cnt] = T[last];
        T[now].val_sum += opt * v;
        T[now].sum += opt;
        if(l == r) return ;
        int mid = l+r >> 1;
        if(val <= mid) Add_node(T[now].lt, T[last].lt, l, mid, val, opt, v);
        else Add_node(T[now].rt, T[last].rt, mid+1, r, val, opt, v);
}

int Query(int rot, int k){
        int lt = T[rot].lt, rt = T[rot].rt;
        if(!lt && !rt) return T[rot].val_sum/T[rot].sum * k;
        int lsum = T[lt].sum, rsum = T[rt].sum;
        if(lsum >= k) return Query(lt, k);
        return T[lt].val_sum + Query(rt, k - lsum);
}

int main(){
        scanf("%d%d", &M, &Q_num);
        for(reg int i = 1; i <= M; i ++){
                scanf("%d%d%d", &ts[i].S, &ts[i].E, &ts[i].P);
                A[++ cnt] = (Cf){ ts[i].S, ts[i].P, 1 };
                A[++ cnt] = (Cf){ ts[i].E+1, ts[i].P, -1 }; // ts[i].E "+1"
                B[++ N] = ts[i].P;
        }
        std::sort(A+1, A+cnt+1, cmp);
        std::sort(B+1, B+N+1);
        Len = std::unique(B+1, B+N+1) - B-1;
        for(reg int i = 1; i <= cnt; i ++){
                A[i].val = std::lower_bound(B+1, B+Len+1, A[i].val) - B;
                Apos[i] = A[i].pos;
        }
        for(reg int i = 1; i <= cnt; i ++) Add_node(rot[i], rot[i-1], 1, Len, A[i].val, A[i].opt, B[A[i].val]);
        int Pre_ans = 1;
        for(reg int i = 1; i <= Q_num; i ++){
                int Xi, Ai, Bi, Ci;
                scanf("%d%d%d%d", &Xi, &Ai, &Bi, &Ci);
                int Ki = 1 + (1ll*Ai*Pre_ans + Bi) % Ci;
                int pos = std::upper_bound(Apos+1, Apos+cnt+1, Xi) - Apos-1;
                if(Ki >= T[rot[pos]].sum) printf("%d
", Pre_ans=T[rot[pos]].val_sum);
                else printf("%d
", Pre_ans=Query(rot[pos], Ki));
        }
        return 0;
}
//Do not confuse the 离散 and the origin value !
//Do remember the root[]'s size need to be large as the T[] !
//All arrays connected to Cf[] need to be large !
原文地址:https://www.cnblogs.com/zbr162/p/11822689.html