【BZOJ3932】【CQOI2015】任务查询系统 可持久化线段树

链接:

#include 
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44937681");
}

题解:

首先肯定要用线段树。
如果没有强制在线,那么直接把询问排个序然后按秩插入、删除、查询。普通线段树就好了,但是这道题强制在线,就需要可持久化线段树了。

线段树的每个区间记录 [x][n]
然后每个版本表示一个时间点的线段树。
这道题每个版本可能有多个节点被修改,所以我们可以先当成多个版本一个个修改,然后最后一个的版本root记录为当前版本root。这样的时空复杂度基本是严格的。
我们还可以修改时传一个修改区间,见我的代码,可以省一部分空间(可卡,但是无论如何理论时间空间一定更优,时间上存在少许常数)。

代码:

#include 
#include 
#include 
#include 
#define N 101000
#define LOGN 35
#define ls s[now].l
#define rs s[now].r
#define inf 0x3f3f3f3f
using namespace std;
struct LSH
{
    int x,id;
    bool operator < (const LSH &A)const{return xstruct OPT
{
    int p,x,d;
    bool operator < (const OPT &A)const{return p==A.p?x1];
struct Segment_Tree
{
    int l,r,n;
    long long x;
}s[N*LOGN];
int cnt,root[N];
inline void pushup(int now)
{
    s[now].x=s[ls].x+s[rs].x;
    s[now].n=s[ls].n+s[rs].n;
}
void add(int last,int &now,int l,int r,int sl,int sr)
{
    now=++cnt;
    if(l==r)
    {
        int t=(sr-sl+1);
        if(seq[sl].d)
        {
            s[now].x=s[last].x+(long long)lsh[l].x*t;
            s[now].n=s[last].n+t;
        }
        else {
            s[now].x=s[last].x-(long long)lsh[l].x*t;
            s[now].n=s[last].n-t;
        }
        return ;
    }
    int mid=l+r>>1;
    if(seq[sr].x<=mid)
    {
        rs=s[last].r;
        add(s[last].l,ls,l,mid,sl,sr);
    }
    else if(seq[sl].x>mid)
    {
        ls=s[last].l;
        add(s[last].r,rs,mid+1,r,sl,sr);
    }
    else {
        int p;
        for(p=sl;seq[p].x<=mid;p++);
        add(s[last].l,ls,l,mid,sl,p-1);
        add(s[last].r,rs,mid+1,r,p,sr);
    }
    pushup(now);
}
long long query(int now,int l,int r,int k)
{
    if(k>=s[now].n)return s[now].x;
    if(l==r)return (long long)k*lsh[l].x;
    int mid=l+r>>1;
    if(s[ls].n>=k)return query(ls,l,mid,k);
    else return s[ls].x+query(rs,mid+1,r,k-s[ls].n);
}
int n,m,u;
long long pre=1;
int getk(int a,int b,int c){return 1+(pre*a+b)%c;}
int main()
{
    int i,j,k;
    int a,b,c;

    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        lsh[i].x=c,lsh[i].id=i;
        seq[i].p=a,seq[i].d=1,seq[i+n].p=b+1;
    }
    sort(lsh+1,lsh+n+1);
    for(i=1;i<=n;i++)
    {
        if(lsh[i].x!=lsh[i-1].x)lsh[++u].x=lsh[i].x;
        seq[lsh[i].id].x=seq[lsh[i].id+n].x=u;
    }
    n<<=1;
    sort(seq+1,seq+n+1);
    for(k=0,i=1;i<=n;i=j)
    {
        for(k++;k1];
            if(k>m)break;
        for(j=i+1;seq[j].p==seq[i].p;j++);
        add(root[k-1],root[k],1,u,i,j-1);
    }
    while(m--)
    {
        scanf("%d%d%d%d",&k,&a,&b,&c);
        pre=query(root[k],1,u,getk(a,b,c));
        printf("%lld\n",pre);
    }
    return 0;
}

你可能感兴趣的:(线段树,可持久化线段树)