p3168 [CQOI2015]任务查询系统(差分+主席树)

时间:2022-11-25 14:42:50

恕我才学浅薄,一开始想到的是树状数组+线段树,然后看了题解才第一次见到了差分这种神奇的科技

仔细想想,主席树的本质不就是前缀和嘛,加上一个差分也是可以的,没想到真是罪过罪过

对时间维护一个差分

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