Shooting HDU

题意:

  在一个射击游戏里面,游戏者可以选择地面上 ([1,X]) 的一个点射击,并且可以在这个点垂直向上射击最近的 (K) 个目标,每个目标有一个价值,价值等于它到地面的距离。游戏中有 (N) 个目标,每个目标从 (L)(R),距离地面高度 (D)。每次射击一个目标可以得到目标价值大小的分数,每次射击以后目标不会消失。如果你前一次游戏得到的分数如果大于 (P),那么这次你得到的分数就翻倍。
数据范围:(1<=N, M ,X<=10^5, P<=10^9)

分析:

主席树。
  根据询问,可以发现是以地面坐标来进行询问的。因此,可以以地面坐标为时间轴,目标的高度为权值建立主席树。但由于询问的结果是可以射击到的目标的高度和,而不是查询区间第 (k) 小。因此,主席树要维护两个东西:1.每个高度的出现次数;2.区间的高度和。对于目标的范围,根据主席树前缀和的思想,在时间 (L) 相应的高度 (+1),在时间 (R+1) 相应的高度 (-1)。记录下每个时间点要进行的操作。
注意:当查询时,由于同一个高度的目标可能有多个,但查询可能不需要全部,所以要减掉一部分。

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,ll>P;
const int N=1e5+5;
int d[N];
vector<P>tar[N];
int root[N],cnt;
struct node
{
    ll sum;
    int num,lson,rson;
}sht[N*40];//N<<5会RE
int get_pos(int h,int len)
{
    return lower_bound(d+1,d+1+len,h)-d;
}
int build(int l,int r)
{
    int t=++cnt;
    if(l==r)
    {
        sht[t].num=0;
        sht[t].sum=0;
        return t;
    }
    int mid=(l+r)>>1;
    sht[t].lson=build(l,mid);
    sht[t].rson=build(mid+1,r);
    sht[t].sum=sht[sht[t].lson].sum+sht[sht[t].rson].sum;
    sht[t].num=sht[sht[t].lson].num+sht[sht[t].rson].num;
    return t;
}
int update(int l,int r,int pos,ll val,int rt)
{
    int t=++cnt;
    sht[t]=sht[rt];
    if(l==r)
    {
        sht[t].num+=val;
        sht[t].sum+=1LL*val*d[pos];
        return t;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        sht[t].lson=update(l,mid,pos,val,sht[rt].lson);
    else
        sht[t].rson=update(mid+1,r,pos,val,sht[rt].rson);
    sht[t].sum=sht[sht[t].lson].sum+sht[sht[t].rson].sum;
    sht[t].num=sht[sht[t].lson].num+sht[sht[t].rson].num;
    return t;
}
P query(int l,int r,ll k,int rt)
{
    if(l==r)
    {
        P tp=make_pair(l,sht[rt].num-k);
        return tp;
    }
    int tn=sht[sht[rt].lson].num;
    int mid=(l+r)>>1;
    if(tn>=k)
        return query(l,mid,k,sht[rt].lson);
    else
        return query(mid+1,r,k-tn,sht[rt].rson);
}
ll query2(int l,int r,int L,int R,int rt)
{
    if(L<=l&&r<=R)
        return sht[rt].sum;
    int mid=(l+r)>>1;
    ll ans=0;
    if(L<=mid)
        ans+=query2(l,mid,L,R,sht[rt].lson);
    if(R>mid)
        ans+=query2(mid+1,r,L,R,sht[rt].rson);
    return ans;
}
int main()
{
    int n,m,X,p,x,a,b,c;
    while(scanf("%d%d%d%d",&n,&m,&X,&p)!=EOF)
    {
        int l,r,h;
        cnt=0;
        for(int i=0;i<=X+1;i++)
            tar[i].clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&l,&r,&h);
            d[i]=h;
            tar[l].pb(make_pair(h,1*1LL));
            tar[r+1].pb(make_pair(h,-1*1LL));
        }
        sort(d+1,d+1+n);
        int len=unique(d+1,d+1+n)-d-1;
        int pos=1;
        root[0]=build(1,len);
        for(int i=1;i<=X;i++)
        {
            if(tar[i].size()==0)
            {
                root[i]=root[i-1];
                continue;
            }
            for(int j=0;j<tar[i].size();j++)
            {
                P t=tar[i][j];
                h=get_pos(t.first,len);
                if(j==0)
                    root[i]=update(1,len,h,t.second,root[i-1]);
                else
                    root[i]=update(1,len,h,t.second,root[i]);
            }
        }
        ll pre=1;
        while(m--)
        {
            scanf("%d%d%d%d",&x,&a,&b,&c);
            ll k=(a*pre+b)%c;
            P tp=query(1,len,k,root[x]);
            ll ans=query2(1,len,1,tp.first,root[x]);
            ans-=1LL*d[tp.first]*(max(tp.second,0*1LL));
            if(pre>p)
                ans*=2;
            printf("%lld
",ans);
            pre=ans;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/1024-xzx/p/12671155.html