区间包含点前k大问题
链接:[P3168 CQOI2015]任务查询系统 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题意:给定多个区间,每个区间有权值 q i q_{i} qi。多次询问经过点 x 的所有区间前 k 小权值的和。
题解:把区间当作两个括号(左括号,右括号),假设题目所求的是区间经过从 x 到结束的前 k 小权值和,那么其实维护右括号即可,按序列长度为时间轴建主席树,按右括号位置插入对应前缀,每次继承上一个时间点或当前时间点建树。查大于等于 x 的点只需要最后一棵树减去第 x-1 棵树即可。但是只经过 x 的区间的话,那么有一些d左括号大于 x 的区间也被算进来。那么再维护一棵左括号的主席树,查询 x 时就可以当作查右括号最后一棵主席树与右括号第 x-1 棵主席树的相减,同时减去左括号 x ( 1 ≤ x ≤ n ) x(1 \le x \le n) x(1≤x≤n) 到 n 的左括号主席树,这样可以消去那些大于 x 的区间的影响。
注意更新函数由于出现自己继承自己的情况,不能提前返回,先保留旧点信息。查询时注意查寻前 k 小时最后 l = r l=r l=r 时返回的值包含的个数可能大于当前所需的个数,所以要减去多的个数。同时可能 k 会大于当前所包含个数,取最大值 max ( 0 , n u m − k ) \max(0,num-k) max(0,num−k)。
//#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
ll b0[maxn],n,m,x,a,b,c,k,ans=1,mx;
int ls[2][maxn<<5],rs[2][maxn<<5],sum[2][maxn<<5],rt[2][maxn],now[2];
ll t[2][maxn<<5];
struct node{
int s,e,p;
}q[maxn];
vector<int>s[maxn],e[maxn];
void update(int o,int u,int&v,int l,int r,int pos)
{
int p=++now[o];
ls[o][p]=ls[o][u],rs[o][p]=rs[o][u];
sum[o][p]=sum[o][u]+1,t[o][p]=t[o][u]+b0[pos];
if(l<r)
{
int mid=l+r>>1;
if(pos<=mid)update(o,ls[o][u],ls[o][p],l,mid,pos);
else update(o,rs[o][u],rs[o][p],mid+1,r,pos);
}
v=p; return;
}
ll query(int u1,int v1,int u2,int v2,int l,int r,int k)
{
int num=sum[1][v2]-sum[1][u2]-sum[0][v1]+sum[0][u1];
if(l==r)return t[1][v2]-t[1][u2]-t[0][v1]+t[0][u1]-max(0,num-k)*b0[l];
int mid=l+r>>1; num=sum[1][ls[1][v2]]-sum[1][ls[1][u2]]-sum[0][ls[0][v1]]+sum[0][ls[0][u1]];
if(k<=num)return query(ls[0][u1],ls[0][v1],ls[1][u2],ls[1][v2],l,mid,k);
else return t[1][ls[1][v2]]-t[1][ls[1][u2]]-t[0][ls[0][v1]]+t[0][ls[0][u1]]+query(rs[0][u1],rs[0][v1],rs[1][u2],rs[1][v2],mid+1,r,k-num);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>m>>n;
for(int i=1;i<=m;i++)
{
cin>>q[i].s>>q[i].e>>q[i].p,b0[i]=q[i].p;
s[q[i].s].push_back(i);
e[q[i].e].push_back(i);
}
sort(b0+1,b0+1+m),mx=unique(b0+1,b0+1+m)-b0-1;
for(int i=1;i<=m;i++)
{
q[i].p=lower_bound(b0+1,b0+1+mx,q[i].p)-b0;
}
for(int i=1;i<=n;i++)
{
if(s[i].size())update(0,rt[0][i-1],rt[0][i],1,mx,q[s[i][0]].p);
else rt[0][i]=rt[0][i-1];
for(int j=1;j<s[i].size();j++)
{
update(0,rt[0][i],rt[0][i],1,mx,q[s[i][j]].p);
}
if(e[i].size())update(1,rt[1][i-1],rt[1][i],1,mx,q[e[i][0]].p);
else rt[1][i]=rt[1][i-1];
for(int j=1;j<e[i].size();j++)
{
update(1,rt[1][i],rt[1][i],1,mx,q[e[i][j]].p);
}
}
for(int i=1;i<=n;i++)
{
cin>>x>>a>>b>>c;
k=1+(a*ans+b)%c;
ans=query(rt[0][x],rt[0][n],rt[1][x-1],rt[1][n],1,mx,k);
cout<<ans<<"\n";
}
return 0;
}