【主席树】 HDOJ 4866

将所有目标与起点线的距离离散化作为下标,建立函数式线段树,将距离按区间端点从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;
}


你可能感兴趣的:(HDU)