BZOJ 3932: [CQOI2015]任务查询系统

http://www.lydsy.com/JudgeOnline/problem.php?id=3932

主席树(可持久化线段树)模板题。

然而我太了,调了1h+,发现询问区间前k大的时候,忘了对重复元素个数判断,导致WA。

做法:把每个任务拆成两个事件,按照时间排序,从前往后建主席树。

然后对每个询问查询区间前k大之和。

贴个版子(指针):

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=300005, MAXS=1e7+5;
int M, N, tot, id[MAXN];
int cnt[MAXN], num[MAXN];
struct Node
{
    Node *lc, *rc;
    int n, l, r;
    ll s;
    inline void up(){
        n=lc->n+rc->n;
        s=lc->s+rc->s;
    }
    ll qry(int k){
        if(l==r) return (ll)num[l]*min(k, n);
        if(k<=lc->n) return lc->qry(k);
        else return lc->s+rc->qry(k-lc->n);
    }
}tr[MAXS], *rt[MAXN];
void upd(Node *&c, Node *t, int x){
    c=&tr[tot++];
    c->l=t->l, c->r=t->r;
    if(c->l==c->r){
        c->n=cnt[x];
        c->s=(ll)cnt[x]*num[x];
        return;
    }
    int mid=(c->l+c->r)>>1;
    if(x<=mid){
        upd(c->lc, t->lc, x);
        c->rc=t->rc;
        c->up();
    }else{
        c->lc=t->lc;
        upd(c->rc, t->rc, x);
        c->up();
    }
}
void build(Node *&x, int l, int r)
{
    x=&tr[tot++];
    x->l=l, x->r=r;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(x->lc, l, mid);
    build(x->rc, mid+1, r);
}
struct Evt{
    int x, t, p;
    bool operator<(const Evt &e) const {return x<e.x;}
}E[MAXN];
int main()
{
    scanf("%d%d", &M, &N);
    for(int i=0; i<M; ++i){
        int s, e, p; scanf("%d%d%d", &s, &e, &p);
        E[i].x=s; E[i].t=1;
        E[i+M].x=e+1; E[i+M].t=0;
        E[i].p=E[i+M].p=p;
        num[i+1]=p;
    }
    sort(num+1, num+M+1); int nt=unique(num+1, num+M+1)-(num+1);
    for(int i=0; i<M; ++i){
        E[i].p=E[i+M].p=lower_bound(num+1, num+1+nt, E[i].p)-num;
    }
    M<<=1;
    sort(E, E+M); E[M++].x=N+1;
    build(rt[0], 1, nt);
    int last=0;
    for(int i=0; i<M; ++i){
        if(E[i].x>last){
            id[last]=i;
            last=E[i].x;
        }
        if(E[i].x>N) break;
        if(E[i].t) cnt[E[i].p]++;
        else cnt[E[i].p]--;
        upd(rt[i+1], rt[i], E[i].p);
    }
    for(int i=1; i<=N; ++i) if(!id[i]) id[i]=id[i-1];
    ll pre=1;
    for(int i=0; i<N; ++i){
        int x, a, b, c;
        scanf("%d%d%d%d", &x, &a, &b, &c);
        a=1+((ll)a*pre+b)%c;
        printf("%lld\n", (pre=rt[id[x]]->qry(a)));
    }
    return 0;
}
posted @ 2017-03-08 22:14  will7101  阅读(181)  评论(0编辑  收藏  举报