bzoj3932[CQOI2015]任务查询系统
传送门
好像还是挺简单的啊,主席树套一套就好了。
本来算错时间复杂度了,以为过不了,去翻题解,发现讲的都是玄学东西,后面终于发现了自己的想法没什么问题,但是还是写不出。
写完后因为5个字节的事情,debug了2小时,真是服了,晚饭也没吃!
时间倒是好解决,差分一下直接查询前缀和就完了,所以首先考虑怎么查询前k小的优先级,我们可以考虑将以优先级为区间来解决这个问题,这个问题就差不多解决了。
因为优先级的范围有点大,要离散化,由于将区间拆成了两个点,所以空间也要翻倍
要开long long
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define int long long
void read(int &x) {
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
map<int,int>mp;
const int maxn=1e5+1;
int id,n,m,pre=1,val[maxn*40],b[maxn*2],rt[maxn*4],tot,ls[maxn*40],rs[maxn*40],size[maxn*40];
struct oo{int l,v;}a[maxn*2];
void update(int x){val[x]=val[ls[x]]+val[rs[x]],size[x]=size[ls[x]]+size[rs[x]];}
void change(int x,int &k,int l,int r,int a,int b)
{
k=++id,val[k]=val[x],ls[k]=ls[x],rs[k]=rs[x],size[k]=size[x];
if(l==r){val[k]+=b,size[k]+=b>0?1:-1;return ;}
int mid=(l+r)>>1;
if(a<=mid)change(ls[x],ls[k],l,mid,a,b);
else change(rs[x],rs[k],mid+1,r,a,b);
update(k);
}
int get(int k,int l,int r,int v)
{
if(l==r)return val[k]/size[k]*v;
int mid=(l+r)>>1;
if(v==size[ls[k]])return val[ls[k]];
else if(v<size[ls[k]])return get(ls[k],l,mid,v);
else return val[ls[k]]+get(rs[k],mid+1,r,v-size[ls[k]]);
}
bool cmp(oo a,oo b){return a.v<b.v;}
bool cmp1(oo a,oo b){return a.l<b.l;}
signed main()
{
read(m),read(n);
for(rg int i=1;i<=m;i++)read(a[i*2-1].l),read(a[i*2].l),read(a[i*2-1].v),a[i*2].l++,a[i*2].v=-a[i*2-1].v;
sort(a+1,a+m*2+1,cmp);
for(rg int i=m+1;i<=m*2;i++)if(!mp[a[i].v])mp[a[i].v]=++tot;
sort(a+1,a+m*2+1,cmp1);int now=1;
for(rg int i=1;i<=n;i++)
{
rt[i]=rt[i-1];
while(now<=2*m&&a[now].l==i)
{
change(rt[i],rt[i],1,tot,mp[a[now].v<0?-a[now].v:a[now].v],a[now].v);
now++;
}
}
for(rg int i=1,x,y,z,v;i<=n;i++)
{
read(x),read(y),read(z),read(v);v=1+(y*pre+z)%v;
if(v>=size[rt[x]])printf("%lld\n",pre=val[rt[x]]);
else printf("%lld\n",pre=get(rt[x],1,tot,v));
}
}