problem
luogu-P3168
solution
主席树板题。
将一个任务拆成 lil_ili 秒开始,ri+1r_i+1ri+1 秒结束的两个任务。
但不建议以每一秒作为一个主席树版本,因为一秒中可能有若干个任务开始或结束。
不妨将所有任务按时刻排序,然后以每个任务作为一个版本。
一次只加入一个单点才是真的板子该有的样子!
然而询问的时候问的是某一秒,所以我们定义一个 End(i)End(i)End(i) 表示 iii 秒结束后对应的最后一个任务版本。
这道题其实不难,但我调了一个晚上!
-
某一秒可能没有任何任务的变化,所以根据写法问题,我必须 End(i)=End(i−1)End(i)=End(i-1)End(i)=End(i−1),不然根本查的就是一个空线段树版本。
-
xxx 版本的前 kkk 小查询。可能有多个任务的权值相同,这意味着线段树上的叶子节点存的个数可能 >1>1>1。
我不能访问到叶子节点就直接返回叶子节点的权值和,而应该是当前的 k′×k'\timesk′× 叶子节点村的权值。
code
#include <bits/stdc++.h>
using namespace std;
#define maxn 200005
#define int long long
int m, n, ans, cnt;
int root[maxn], End[maxn], val[maxn];
struct option { int x, v, k; }g[maxn];
struct node { int cnt, sum, lson, rson; }t[maxn * 40];void modify( int lst, int &now, int l, int r, int p, int k ) {now = ++ cnt, t[now] = t[lst];if( l == r ) { t[now].cnt += k; t[now].sum += k * val[p]; return; };int mid = l + r >> 1;if( p <= mid ) modify( t[lst].lson, t[now].lson, l, mid, p, k );else modify( t[lst].rson, t[now].rson, mid + 1, r, p, k );t[now].cnt = t[t[now].lson].cnt + t[t[now].rson].cnt;t[now].sum = t[t[now].lson].sum + t[t[now].rson].sum;
}int query( int now, int l, int r, int k ) {if( t[now].cnt <= k ) return t[now].sum;if( l == r ) return k * val[l];int mid = l + r >> 1;if( k <= t[t[now].lson].cnt ) return query( t[now].lson, l, mid, k );else return query( t[now].rson, mid + 1, r, k - t[t[now].lson].cnt ) + t[t[now].lson].sum;
}signed main() {scanf( "%lld %lld", &m, &n );for( int i= 1, l, r, k;i <= m;i ++ ) {scanf( "%lld %lld %lld", &l, &r, &k );g[i] = (option){ l, k, 1 };g[i + m] = (option){ r + 1, k, -1 };val[i] = k;}sort( val + 1, val + m + 1 );int tot = unique( val + 1, val + m + 1 ) - val - 1;m <<= 1;sort( g + 1, g + m + 1, []( option a, option b ) { return a.x < b.x; } );for( int i = 1;i <= m;i ++ ) g[i].v = lower_bound( val + 1, val + tot + 1, g[i].v ) - val;for( int i = 1, j = 1;i <= n;i ++ ) {End[i] = End[i - 1];for( ;j <= m and g[j].x <= i;j ++ ) {modify( root[j - 1], root[j], 1, tot, g[j].v, g[j].k );End[i] = j;}}ans = 1;for( int i = 1, x, a, b, c;i <= n;i ++ ) {scanf( "%lld %lld %lld %lld", &x, &a, &b, &c );int k = ( a * ans + b ) % c + 1;printf( "%lld\n", ans = query( root[End[x]], 1, tot, k ) );}return 0;
}