#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;
}