题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3932
第二道主席树!本来想自己手胡一下,但是还是写不下去了...
参考博客:https://www.cnblogs.com/CQzhangyu/p/6295579.html
就是对每个时间节点建一棵权值线段树,节点太多所以开成主席树;
WA了好久,竟然是错在二分的地方了???看了半天还是不知道为什么错,那个写法已经用了好久了啊...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const maxn=2e5+5; ll n,m,ls[maxn*40],rs[maxn*40],siz[maxn*40],tot,rt[maxn],cnt; ll sum[maxn*40],ans,t[maxn]; struct N{ll t,v,k;}p[maxn]; bool cmp1(N x,N y){return x.v<y.v;} bool cmp2(N x,N y){return x.t<y.t;} void pushup(ll x) { siz[x]=siz[ls[x]]+siz[rs[x]]; sum[x]=sum[ls[x]]+sum[rs[x]]; } void insert(ll u,ll &v,ll l,ll r,ll pos,ll val) { v=++cnt; if(l==r) { siz[v]=siz[u]+val; sum[v]=sum[u]+t[pos]*val; return; } ls[v]=ls[u]; rs[v]=rs[u]; sum[v]=sum[u]; siz[v]=siz[u]; ll mid=((l+r)>>1); if(pos<=mid)rs[v]=rs[u],insert(ls[u],ls[v],l,mid,pos,val); else ls[v]=ls[u],insert(rs[u],rs[v],mid+1,r,pos,val); pushup(v); } ll query(ll x,ll l,ll r,ll pos) { if(l==r)return t[l]*pos;//*pos! ll mid=((l+r)>>1); if(siz[ls[x]]>=pos)return query(ls[x],l,mid,pos); else return sum[ls[x]]+query(rs[x],mid+1,r,pos-siz[ls[x]]); } int main() { scanf("%lld%lld",&m,&n); for(ll i=1,x,y,z;i<=m;i++) { scanf("%lld%lld%lld",&x,&y,&z); p[i*2-1].t=x; p[i*2].t=y+1; p[i*2-1].v=p[i*2].v=z; p[i*2-1].k=1; p[i*2].k=-1; } sort(p+1,p+2*m+1,cmp1);//v for(ll i=1;i<=2*m;i++)//离散化 { if(p[i].v!=t[tot])t[++tot]=p[i].v; p[i].v=tot; } sort(p+1,p+2*m+1,cmp2);//t for(ll i=1;i<=2*m;i++)//权值线段树 insert(rt[i-1],rt[i],1,tot,p[i].v,p[i].k); ans=1; for(ll i=1,x,a,b,c,k;i<=n;i++) { scanf("%lld%lld%lld%lld",&x,&a,&b,&c); k=1+(a*ans+b)%c; // ll l=1,r=2*m+1,nw; // while(l<=r)//二分找到该节点线段树 // { // ll mid=((l+r)>>1); // if(p[mid].t<=x)nw=mid,l=mid+1; // else r=mid-1; // } ll l=1,r=2*m+1,mid;//写成r=2*n-1竟然也过了,数据... while(l<r) { mid=l+r>>1; if(p[mid].t<=x) l=mid+1; else r=mid; } ll nw=l-1; if(siz[rt[nw]]<=k)ans=sum[rt[nw]]; else ans=query(rt[nw],1,tot,k); printf("%lld ",ans); } return 0; }