p3168 [CQOI2015]任務查詢系統(差分+主席樹)
阿新 • • 發佈:2018-11-25
恕我才學淺薄,一開始想到的是樹狀陣列+線段樹,然後看了題解才第一次見到了差分這種神奇的科技
仔細想想,主席樹的本質不就是字首和嘛,加上一個差分也是可以的,沒想到真是罪過罪過
對時間維護一個差分
在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; }