题目链接:点击查看
题目大意:给出 n 条平行于 x 轴的线段,每条线段都的 [ l , r ] 都位于 [ 1 , X ] 之间,每条线段的高度为 d,也就是距离 x 轴的位置,接下来给出 m 次询问,每次询问给出一个 x 和 k ,问:在点 x 处向上的前 k 个线段的高度之和为多少,如果 k 大于点 x 处的线段总数,那么缺少的线段用最高的线段的高度补上
题目分析:因为题目要求了强制在线,所以不能用线段树+离线来完成,区间 [ 1 , X ] 上的每个点可以通过扫描线的思想,将 n 条线段的属性转换为前缀和的思想,这样每个点都可以独立成为一个前缀和的版本了,所有的版本可以利用主席树来维护,每个版本中维护当前所有线段高度的前缀和,这样每次查询时,只需要查询第 x 个版本的主席树,在内部二分找到 k 的位置,然后返回前缀即可,对于 k 不足的地方,在 l == r 的地方稍微处理一下就可以了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
vector<int>v,node[N];
/*主席树*/
struct Node
{
int l,r,num;
LL sum;
}tree[N*50];
int cnt,root[N];
void init()
{
root[0]=0;
tree[0].l=tree[0].r=tree[0].sum=tree[0].num=0;
cnt=1;
}
void update(int pos,int flag,int &k,int l,int r)
{
tree[cnt++]=tree[k];
k=cnt-1;
tree[k].num+=flag;
tree[k].sum+=flag*v[pos-1];
if(l==r)
return;
int mid=l+r>>1;
if(pos<=mid)
update(pos,flag,tree[k].l,l,mid);
else
update(pos,flag,tree[k].r,mid+1,r);
}
LL query(int rt,int k,int l,int r)
{
if(l==r)
return 1LL*v[l-1]*k;
int mid=l+r>>1;
int num=tree[tree[rt].l].num;
LL sum=tree[tree[rt].l].sum;
if(num>=k)
return query(tree[rt].l,k,l,mid);
else
return sum+query(tree[rt].r,k-num,mid+1,r);
}
/*主席树*/
/*离散化*/
void discreate()
{
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
}
int get_id(int x)
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
/*离散化*/
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m,X,P;
while(scanf("%d%d%d%d",&n,&m,&X,&P)!=EOF)
{
init();
for(int i=1;i<=X+1;i++)
node[i].clear();
for(int i=1;i<=n;i++)
{
int l,r,d;
scanf("%d%d%d",&l,&r,&d);
node[l].push_back(d);
node[r+1].push_back(-d);
v.push_back(d);
}
discreate();
for(int i=1;i<=X;i++)
{
root[i]=root[i-1];
for(auto t:node[i])
update(get_id(abs(t)),t<0?-1:1,root[i],1,v.size());
}
LL pre=1;
while(m--)
{
int x,a,b,c;
scanf("%d%d%d%d",&x,&a,&b,&c);
int k=(pre*a+b)%c;
LL ans=query(root[x],k,1,v.size());
if(pre>P)
ans*=2;
printf("%lld\n",ans);
pre=ans;
}
}
return 0;
}