将所有目标与起点线的距离离散化作为下标,建立函数式线段树,将距离按区间端点从1到X的顺序加入函数式线段树,左端点+1,右端点-1,记录区间元素的距离和,以及元素的个数。对于在x位置的询问,找到其对应的端点,这个可以二分找到,然后在该端点对应的线段树上进行二分查找求解,最后判断前一个答案与P的大小得到当前问题的答案。。。。注意有线段可能完全重合。。。
#include <iostream> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <algorithm> #include <cstring> #include <climits> #include <cstdlib> #include <cmath> #include <time.h> #define maxn 100005 #define eps 1e-10 #define mod 1000000009 #define INF 99999999 #define lowbit(x) (x&(-x)) //#define lson o<<1, L, mid //#define rson o<<1 | 1, mid+1, R typedef long long LL; //typedef int LL; using namespace std; struct Edge { int a, d, op; }e[maxn<<1]; int dd[maxn]; int dcnt; struct node { node *lson, *rson; LL val, sum; void maintain(void) { sum = lson->sum + rson->sum; val = lson->val + rson->val; } }*root[maxn<<2], C[maxn*40], *null, *top; int n, m, v; int x, p; int cmp(int a, int b) { return a<b; } int cmp1(Edge a, Edge b) { return a.a < b.a; } void read(void) { int i, aa, bb, d, cont = 0; dcnt = 0; for(i = 0; i < n; i++) { scanf("%d%d%d", &aa, &bb, &d); e[cont].a = aa, e[cont].d = d, e[cont].op = 1, cont++; e[cont].a = bb+1, e[cont].d = d, e[cont].op = -1, cont++; dd[++dcnt] = d; } n = cont; } void work(void) { int i, j; sort(dd+1, dd+1+dcnt, cmp); for(i = 2, j = 2; i <= dcnt; i++) if(dd[i] == dd[j]) dd[j++] = dd[i]; dcnt = j-1; sort(e, e+n, cmp1); } int search(int tmp) { int bot = 1, top = dcnt, mid; while(top >= bot) { mid = (top+bot)>>1; if(dd[mid] == tmp) break; if(dd[mid] > tmp) top = mid-1; else bot = mid+1; } return mid; } void init(void) { top = C; null = top++; null->val = null->sum = 0; null->lson = null->rson = NULL; } node* build(int L, int R) { node *newroot = top++; newroot->val = newroot->sum = 0; if(L == R) { newroot->lson = newroot->rson = null; return newroot; } int mid = (L+R)>>1; newroot->lson = build(L, mid); newroot->rson = build(mid+1, R); return newroot; } node* updata(node* o, int d, int L, int R) { node *now = top++; if(L == R){ now->val = o->val + d; now->sum = o->sum + dd[v]*d; now->lson = now->rson = null; return now; } int mid = (L+R)>>1; if(v <= mid) { now->lson = updata(o->lson, d, L, mid); now->rson = o->rson; } else { now->lson = o->lson; now->rson = updata(o->rson, d, mid+1, R); } now->maintain(); return now; } LL kth(node *o, int k) { if(o->lson == null && o->rson == null) { if(o->val != 0) return (LL)k*o->sum/o->val; else return 0; } if(k <= o->lson->val) return kth(o->lson, k); return o->lson->sum + kth(o->rson, k - o->lson->val); } void solve(void) { root[0] = build(1, dcnt); for(int i = 1, j = 0; i <= x; i++) { root[i] = root[i-1]; while(j<n && e[j].a <= i) { v = search(e[j].d); root[e[j].a] = updata(root[e[j].a], e[j].op, 1, dcnt); j++; } } } /* void debug(void) { for(int i = 0; i <= x; i++) printf("AAA %d %d BBB\n", root[i]->val, root[i]->sum); } */ void task(void) { int k; LL xx, a, b, c, pre = 1, now; while(m--) { scanf("%I64d%I64d%I64d%I64d", &xx, &a, &b, &c); k = (a*pre + b)%c; now = kth(root[xx], k); if(pre > p) now*=2; printf("%I64d\n", pre = now); } } int main(void) { while(scanf("%d%d%d%d", &n, &m, &x, &p)!=EOF) { init(); read(); work(); solve(); task(); } return 0; }