bzoj3932 [CQOI2015]任务查询系统——主席树

题目: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\n",ans);
    }
    return 0;
}

 

posted @ 2018-07-19 19:27  Zinn  阅读(105)  评论(0编辑  收藏  举报