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;
}
退役