bzoj3932: [CQOI2015]任务查询系统(主席树)

bzoj3932: [CQOI2015]任务查询系统(主席树)

[CQOI2015]任务查询系统

思路

    按时间顺序建权值线段树,对于每个三元组,在Si的树上Pi的位置+1,Ei+1的树上Pi的位置-1,这样对于每次询问的时间区间T[r] - T[l-1]求前k个的和就行了,需要注意的是询问的时候当l==r时这个位置的值不能全部取走,要取走相应的剩下的那k个。

代码

#include 
using namespace std;
#define dd(x) cout<<#x<<"="< vi;
typedef pair  pi;
int T[maxn<<7],  l[maxn<<7], r[maxn<<7];
ll sum[maxn<<7];
int cnt,s[maxn<<7], n, m;
vector  vv; 
vector < pair < int ,ll > > v;
void upd(int pre, int &now,int L,int R,int t,ll p){
    now = ++cnt; 
    sum[now]=sum[pre]+p;
    s[now]=s[pre]+p/abs(p);
    l[now]=l[pre];
    r[now]=r[pre];
    if(L==R) return ;
    int mid= L+R>>1;
    if(t<=mid )upd(l[pre],l[now],L,mid,t,p);
    else upd(r[pre],r[now],mid+1,R,t,p);
}
ll qr(int now ,int k,int L,int R ){
    if(L==R){
        return 1ll*k*sum[now]/s[now];
    }
    if(s[now]==0) return 0;
    int mid = L+R>>1;
    if(k>s[l[now]])  return qr(r[now], k-s[l[now]],mid+1,R)+sum[l[now]];
    return qr(l[now],k,L,mid);
}
int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin>> n>> m;
    rep(i,0,n){
        int l,r;
        ll p;
        cin>> l >> r>> p;
        v.pb({l,p});
        v.pb({r+1,-p});
        vv.pb(p);
    }
    sort(all(vv));
    vv.erase(unique(all(vv)),vv.end());
    int t=0, mm=sz(vv);
    sort(all(v));
    rep(i,1,m+1){
        T[i] = T[i-1];
        while(t>x>>a>> b>> c;
        pre%=c;
        k = 1+(a*pre%c+b)%c;
        if(k> s[T[x]] ) pre = 1ll*sum[T[x]];
        else pre=qr(T[x],k,1,sz(vv));
        cout << pre << endl; 
    }
    return 0;
}

你可能感兴趣的:(bzoj3932: [CQOI2015]任务查询系统(主席树))