hdu5140 Hun Gui Wei Company题解 主席树
这个题还是比较模板的。等级和年限这两个参数,一个当成下标,一个当成值域(应该是这么叫的吧)。
假设以level为下标建立主席树,age作为值域,那我们可以把所有员工的level离散化。因为这个题强制在线,我们没有办法把查询的level离散化,但是我们可以每次二分,找到这个询问对应着的范围。我偷懒没有离散化age,写的动态开点。
需要注意的几个点:
- 模板要写对,我因为这个调了一整天。
- 还有二分的问题,算是个小套路,大家都知道
lower_bound(a+1,a+n+1,x)-a
,二分最后一个<=x的数可以用upper_bound(a+1,a+n+1,x)-a-1
。这两个式子的取值范围分别是\([1,n+1]\)和\([0,n]\)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
#define forg(i,x) for(int i=first[x];i;i=nxt[i])
#define forl(z,i,x) for(int i=z.first[x],y=z.to[i];i;i=z.nxt[i],y=z.to[i])
#define uu unsigned
#define fi first
#define se second
#define ran() ((unsigned)rand())
#define lam(z,k) [&](const z &a,const z &b){ return k; }
#define od(x) ((x)&1)
#define ev(x) (od(x)^1)
#define lson(x) tr[x].lson
#define rson(x) tr[x].rson
const int mxn=1e5+3,mxm=mxn,siz=1e9;const long long cc=1e17;
int n,m,nn;
struct worker{
int gz,dj,tm;//工资 等级 时间
}a[mxn];
int lsd[mxn];
inline int getls(int x){
return lower_bound(lsd+1,lsd+nn+1,x)-lsd;
}
class zxs{
public:
struct a_w{
int lson,rson;
long long sum;
}tr[mxn*50];
int RT[mxn],tot;
inline void clear(){
memset(RT,0,sizeof(RT));
for(int i=1;i<=tot;++i)tr[i].sum=lson(i)=rson(i)=0;
tot=0;
}
inline void dadd(int &p,int pre,int l,int r,int pc,int kc){
//单点修改
int mid=(l+r)>>1;
if(p==0||p==pre){
p=++tot; if(pre)tr[p]=tr[pre];
}
if(l==r)return tr[p].sum+=kc,void();
if(pc<=mid)dadd(lson(p),lson(pre),l,mid,pc,kc);
else dadd(rson(p),rson(pre),mid+1,r,pc,kc);
pushup(p);
}
inline void pushup(int x){
tr[x].sum=tr[lson(x)].sum+tr[rson(x)].sum;
}
inline long long ask(int x1,int x2,int l,int r,int lc,int rc){
int mid=(l+r)>>1;
if(!x1&&!x2)return 0;
if(lc<=l&&r<=rc)return tr[x2].sum-tr[x1].sum;
long long res=0;
if(lc<=mid)res+=ask(lson(x1),lson(x2),l,mid,lc,rc);
if(rc>mid)res+=ask(rson(x1),rson(x2),mid+1,r,lc,rc);
return res;
}
}seg;
class hah{public:void a(){b();}void b(){a();}}emm;
inline int getdj2(int x){
int l=0,r=nn,mid;
while(l!=r){
mid=(l+r+1)>>1;
if(lsd[mid]<=x)l=mid;
else r=mid-1;
}
return l;
}
int main(){
while(~scanf("%d",&n)){
seg.clear();
for(int i=1;i<=n;++i)scanf("%d%d%d",&a[i].gz,&a[i].dj,&a[i].tm),lsd[i]=a[i].dj;
scanf("%d",&m);
sort(lsd+1,lsd+n+1);nn=unique(lsd+1,lsd+n+1)-(lsd+1);
for(int i=1;i<=n;++i)a[i].dj=getls(a[i].dj);
sort(a+1,a+n+1,lam(worker,a.dj<b.dj));
for(int i=1,p=1;i<=nn&&p<=n;++i){
int &kk=seg.RT[i];
for(;a[p].dj==i&&p<=n;++p){
seg.dadd(kk,seg.RT[i-1],1,siz+1,a[p].tm+1,a[p].gz);
}
if(!kk)kk=seg.RT[i-1];//这句可以省略,因为离散化以后是连续的
}
lsd[0]=-233,lsd[nn+1]=siz+233;
long long lstans=0;
for(int i=1;i<=m;++i){
static long long dj1,dj2,tm1,tm2;scanf("%lld%lld%lld%lld",&dj1,&dj2,&tm1,&tm2);
dj1+=lstans,dj2-=lstans,tm1+=lstans,tm2-=lstans;
if(dj1>dj2)swap(dj1,dj2);if(tm1>tm2)swap(tm1,tm2);
dj1=max(dj1,0ll),tm1=max(tm1,0ll),dj2=min(dj2,(long long)siz),tm2=min(tm2,(long long)siz);
if(dj1>dj2){puts("0");lstans=0;continue;}//特判
int aa=dj1,bb=dj2;
dj1=getls(dj1),dj2=upper_bound(lsd+1,lsd+nn+1,dj2)-lsd-1;//getdj2(dj2)
if(!(lsd[dj1]>=aa&&lsd[dj1-1]<aa && lsd[dj2]<=bb&&lsd[dj2+1]>bb))return puts("whatawht"),emm.a(),33333;
//检查二分的结果是否合法 这句不加也可以
// first>=dj1 last<=dj2
if(dj1>dj2||tm1>tm2){puts("0");lstans=0;continue;}//特判
printf("%lld\n",lstans= seg.ask(seg.RT[dj1-1],seg.RT[dj2],1,siz+1,tm1+1,tm2+1));
}
}
return 0;
}