题意:
有n条平行于x轴的线段,m次射击,每次射击射中前k个线段,得到的分数为 其中 为线段到x轴距离,k为 ,pre为上次得分,并且如果pre大于p,那么本次得分翻倍
思路:
主席树处理出的是一个前缀和,而利用差分,就能很好的染出一片区域。意思就是,对于每条线段,我们在
处
,在
,然后我们对于每一个x坐标建立一棵线段树,这样就能产生一颗主席树。我们可以发现,这样的树,可以维护每个x轴坐标上的线段情况,我们维护num和sum两个数组,一个记录此时下面有几个点,一个维护分数和,在每次射击的时候,利用数量向下走即可
注意,可能出现线段重合的情况,这时候需要加一些判断
更新:和任务查询系统一模一样。。。
错误及反思:
代码:
#include<bits/stdc++.h>
using namespace std;
#define lson l,m
#define rson m+1,r
#define fi first
#define se second
const int N = 200010;
int ls[N*30],rs[N*30],num[N*30],n,m,x,p,cnt,root[N];
long long sum[N*30];
vector<int> v;
struct LINE{
int l,r,d;
}line[N];
vector<pair<int,int> > need[N];
int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
void init(){
cnt=0;
v.clear();
}
int build(int l,int r){
int rt=++cnt;
ls[rt]=rt; rs[rt]=rt; sum[rt]=0; num[rt]=0;
if(l==r) return rt;
int m=l+r>>1;
ls[rt]=build(lson);
rs[rt]=build(rson);
return rt;
}
int update(int pre,int val,int pos,int l,int r){
int rt=++cnt;
sum[rt]=sum[pre]+val; ls[rt]=ls[pre]; rs[rt]=rs[pre]; num[rt]=num[pre]+(val>0?1:-1);
if(l==r) return rt;
int m=l+r>>1;
if(m>=pos) ls[rt]=update(ls[pre],val,pos,lson);
else rs[rt]=update(rs[pre],val,pos,rson);
return rt;
}
long long query(int r2,int k,int l,int r){
if(l==r){
if(num[r2]==0) return 0;
if(num[r2]>=k)
return sum[r2]/num[r2]*k;
return sum[r2];
}
int m=l+r>>1;
if(num[ls[r2]]>=k) return query(ls[r2],k,lson);
return sum[ls[r2]]+query(rs[r2],k-num[ls[r2]],rson);
}
int main(){
while(scanf("%d%d%d%d",&n,&m,&x,&p)!=EOF){
init();
for(int i=1;i<=n;i++){
scanf("%d%d%d",&line[i].l,&line[i].r,&line[i].d);
v.push_back(line[i].d);
}
sort(v.begin(),v.end()),v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++){
need[line[i].l].push_back({getid(line[i].d),line[i].d});
need[line[i].r+1].push_back({getid(line[i].d),-line[i].d});
}
root[0]=build(1,v.size());
for(int i=1;i<=x;i++){
int bef=root[i-1];
for(int j=0;j<need[i].size();j++){
bef=update(bef,need[i][j].se,need[i][j].fi,1,v.size());
}
root[i]=bef;
}
long long pre=1;
while(m--){
int xx,a,b,c;
scanf("%d%d%d%d",&xx,&a,&b,&c);
long long k=(1ll*a*pre+b)%c;
k=query(root[xx],(int)k,1,v.size());
if(pre>p) k*=2;
pre=k;
printf("%lld\n",pre);
}
for(int i=1;i<=x+1;i++) need[i].clear();
}
}