在一个平面直角坐标系上,有一些靶子,靶子可以视为平行于x轴的线段,有一个人站在某个位置打靶,打靶的方向永远是y轴正方向。他每次可以打穿前k-1个靶子,所以共击中前k个靶子,击中一个靶子可以得到那个靶子与x轴的距离的分数。靶子被击中后仍然存在。问这个人每次打靶得到的分数。如果之前打靶的分数超过了p,那么下次打靶得到的分数会乘2。
数据范围:x轴大小为10^5,y轴大小为10^7,k为每次根据上一次结果和输入数据给的一些参数计算得出。
做法:把靶子按照y轴坐标排序,用一棵可持久化线段树,按照距离依次将靶子添加到线段树上,即能打到这个靶子的区间整体加上这个靶子的分数。查询时先二分答案,判断他能打到前k个靶子是具体能打到排序后的第几个靶子,然后在对应的线段树上查询能得到的分数。
由于内存要求不够,所以又把区间修改点查询转换成了点修改区间查询。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct SegTreeNode {
SegTreeNode *ls,*rs;
long long score;
int count;
};
SegTreeNode a[4000000];
SegTreeNode *acur;
struct PersistentSegTree {
SegTreeNode *root[200001];
SegTreeNode *maketree(int l,int r) {
SegTreeNode *ans=acur++;
ans->score=ans->count=0;
if (l==r) {
ans->ls=ans->rs=NULL;
} else {
int t=(l+r)/2;
ans->ls=maketree(l,t);
ans->rs=maketree(t+1,r);
}
return ans;
}
void clear(int l,int r) {
acur=a;
root[0]=maketree(l,r);
}
SegTreeNode *set(SegTreeNode *from,int l,int r,int pos,int x) {
//printf("%d %d %d %d %d\n",l,r,ll,rr,x);
SegTreeNode *ans=acur++;
*ans=*from;
if (l==r) {
ans->score+=x;
if (x>0) ans->count++;
else ans->count--;
} else {
int t=(l+r)/2;
if (pos<=t) {
ans->ls=set(from->ls,l,t,pos,x);
} else {
ans->rs=set(from->rs,t+1,r,pos,x);
}
ans->score=ans->ls->score+ans->rs->score;
ans->count=ans->ls->count+ans->rs->count;
}
//printf("%lld %d\n",ans->score,ans->count);
return ans;
}
int getnum(SegTreeNode *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr) return from->count;
int t=(l+r)/2;
if (rr<=t) {
return getnum(from->ls,l,t,ll,rr);
} else if (ll>t) {
return getnum(from->rs,t+1,r,ll,rr);
} else {
return getnum(from->ls,l,t,ll,t)+getnum(from->rs,t+1,r,t+1,rr);
}
}
long long getscore(SegTreeNode *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr) return from->score;
int t=(l+r)/2;
if (rr<=t) {
return getscore(from->ls,l,t,ll,rr);
} else if (ll>t) {
return getscore(from->rs,t+1,r,ll,rr);
} else {
return getscore(from->ls,l,t,ll,t)+getscore(from->rs,t+1,r,t+1,rr);
}
}
};
struct Target{
int l,r,d;
void read() {
scanf("%d%d%d",&l,&r,&d);
}
friend bool operator < (const Target &a,const Target &b) {
return a.d<b.d;
}
};
int n,m,maxx,p;
Target b[100000];
PersistentSegTree c;
int main() {
int i;
long long pre;
while (scanf("%d%d%d%d",&n,&m,&maxx,&p)!=EOF) {
for (i=0;i<n;i++) {
b[i].read();
}
sort(b,b+n);
maxx++;
c.clear(1,maxx);
//printf("Build 0 complete\n");
for (i=0;i<n;i++) {
c.root[i*2+1]=c.set(c.root[i*2],1,maxx,b[i].l,b[i].d);
c.root[i*2+2]=c.set(c.root[i*2+1],1,maxx,b[i].r+1,-b[i].d);
//printf("Build %d complete\n",i+1);
}
//printf("Build complete\n");
pre=1;
for (i=0;i<m;i++) {
int xx,k,aa,bb,cc;
scanf("%d%d%d%d",&xx,&aa,&bb,&cc);
k=(aa*pre+bb)%cc;
int l=0,r=n;
while (l!=r) {
int t=(l+r)/2;
int tmp=c.getnum(c.root[t*2],1,maxx,1,xx);
if (tmp<k) l=t+1;
else r=t;
}
//printf("%d %d\n",k,c.getnum(c.root[l],1,maxx,xx));
long long ans=c.getscore(c.root[l*2],1,maxx,1,xx);
if (pre>p) ans*=2;
printf("%I64d\n",ans);
pre=ans;
}
//static int cas=1;
//cerr<<cas++<<"complete\n";
//cerr<<acur-a<<endl;
}
return 0;
}
附上原来的点修改区间查询版本...内存超了30M....
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct SegTreeNode {
SegTreeNode *ls,*rs;
long long score;
int count;
};
SegTreeNode a[8000000];
SegTreeNode *acur;
struct PersistentSegTree {
SegTreeNode *root[100001];
SegTreeNode *maketree(int l,int r) {
SegTreeNode *ans=acur++;
ans->score=ans->count=0;
if (l==r) {
ans->ls=ans->rs=NULL;
} else {
int t=(l+r)/2;
ans->ls=maketree(l,t);
ans->rs=maketree(t+1,r);
}
return ans;
}
void clear(int l,int r) {
acur=a;
root[0]=maketree(l,r);
}
SegTreeNode *set(SegTreeNode *from,int l,int r,int ll,int rr,int x) {
//printf("%d %d %d %d %d\n",l,r,ll,rr,x);
SegTreeNode *ans=acur++;
*ans=*from;
if (l==ll&&r==rr) {
ans->score+=x;
ans->count++;
} else {
int t=(l+r)/2;
if (rr<=t) {
ans->ls=set(from->ls,l,t,ll,rr,x);
} else if (ll>t) {
ans->rs=set(from->rs,t+1,r,ll,rr,x);
} else {
ans->ls=set(from->ls,l,t,ll,t,x);
ans->rs=set(from->rs,t+1,r,t+1,rr,x);
}
}
//printf("%lld %d\n",ans->score,ans->count);
return ans;
}
int getnum(SegTreeNode *from,int l,int r,int x) {
int count=0;
while (l!=r) {
count+=from->count;
int t=(l+r)/2;
if (x<=t) {
r=t;
from=from->ls;
} else {
l=t+1;
from=from->rs;
}
}
count+=from->count;
return count;
}
long long getscore(SegTreeNode *from,int l,int r,int x) {
long long score=0;
while (l!=r) {
score+=from->score;
int t=(l+r)/2;
if (x<=t) {
r=t;
from=from->ls;
} else {
l=t+1;
from=from->rs;
}
};
score+=from->score;
return score;
}
};
struct Target{
int l,r,d;
void read() {
scanf("%d%d%d",&l,&r,&d);
}
friend bool operator < (const Target &a,const Target &b) {
return a.d<b.d;
}
};
int n,m,maxx,p;
Target b[100000];
PersistentSegTree c;
int main() {
int i;
long long pre;
while (scanf("%d%d%d%d",&n,&m,&maxx,&p)!=EOF) {
for (i=0;i<n;i++) {
b[i].read();
}
sort(b,b+n);
c.clear(1,maxx);
for (i=0;i<n;i++) {
//printf("-- %d %d %d\n",b[i].l,b[i].r,b[i].d);
c.root[i+1]=c.set(c.root[i],1,maxx,b[i].l,b[i].r,b[i].d);
}
pre=1;
/*
for (i=0;i<=n;i++) {
printf("%dth tree\n",i);
for (int j=1;j<=maxx;j++) printf("%d ",c.getnum(c.root[i],1,maxx,j));
printf("\n");
for (int j=1;j<=maxx;j++) printf("%lld ",c.getscore(c.root[i],1,maxx,j));
printf("\n");
}
*/
for (i=0;i<m;i++) {
int xx,k,aa,bb,cc;
scanf("%d%d%d%d",&xx,&aa,&bb,&cc);
k=(aa*pre+bb)%cc;
int l=0,r=n;
while (l!=r) {
int t=(l+r)/2;
int tmp=c.getnum(c.root[t],1,maxx,xx);
if (tmp<k) l=t+1;
else r=t;
}
//printf("%d %d\n",k,c.getnum(c.root[l],1,maxx,xx));
long long ans=c.getscore(c.root[l],1,maxx,xx);
if (pre>p) ans*=2;
printf("%lld\n",ans);
pre=ans;
}
//static int cas=1;
//cerr<<cas++<<"complete\n";
//cerr<<acur-a<<endl;
}
return 0;
}