hdu4866(可持久化线段树)

Shooting

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2777    Accepted Submission(s): 638

Problem Description

In the shooting game, the player can choose to stand in the position of [1, X] to shoot, you can shoot all the nearest K targets. The value of K may be different on different shootings. There are N targets to shoot, each target occupy the position of [Li, Ri] , the distance from the starting line is Di(1<=i<=N). Shooting a target can get the bonus points equal to the distance to the starting line. After each shooting targets still exist. Additional, if the previous bonus points is more than P, then as a reward for the shooting present bonus points doubled(and then check the next one). Player wants to know the bonus points he got in each shot.

Input

The input consists several test cases. 
The first line has two integers, N, M, X, P(1<=N, M ,X<=100000, P<=1000000000), N represents the total number of target shooting, M represents the number of shooting. 
The next N lines of three integers L, R, D (1<=L<=R<=X, 1<=D<=10000000), occupy the position of [L, R] and the distance from the starting line is D. 
The next M lines, each line contains four integers x, a, b, c (1<=x<=X, 0<=a,b<=N, 1<=c<=10000000), and K = ( a * Pre + b ) % c. Pre is the bonus point of previous shooting , and for the first shooting Pre=1. It denotes standing in the position x and the player can shoot the nearest K targets.

Output

Output M lines each corresponds to one integer.

Sample Input

4 3 5 8

1 2 6

2 3 3

2 4 7

1 5 2

2 2 1 5

3 1 1 10

4 2 3 7

 

题意:在二维空间中有一些平行于x轴的线段,现在有m次,每次在x轴上一个点去垂直x轴射击他们,每次只能射击邻近的k个线段,k可由题中公式算出,射击每个线段的得分为它到x轴距离,且射击后下一次射击那条线段还在,每次射击分数大于p,下一次射击的分数会变双倍。问每一次射击所得分数。

思路:根据线段到x轴的距离建主席树(需要hash一下),扫描线,x从左往右扫描,没扫描到一个线段的左端点,插入主席树,相应距离的cnt和val++,遇到右端点则相应的cnt和val--,查询的时候,二分到对应的root,查询前k个的val和。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 100010;
const int inf = 0x3fffffff;
int n,m,X;
ll p;
struct pnode
{
    int flag;
    int d;
    int x;
    bool operator < (const pnode &b) const 
    {
        if(x!=b.x)return x<b.x;
        if(d!=b.d)return d<b.d;
        return x<b.x;    
    }
}tag_point[maxn<<1];
int dis[maxn];
map<int,bool>mp;
struct  node
{
    int chl,chr;
    int cnt;
    ll val;
}t[maxn*35];
int root[maxn<<2];
int tot = 0;
void build(int &x,int l,int r) {
    x=++tot;
    t[x].cnt = 0;
    t[x].val = 0;   
    if (l==r) return ;
    int mid=(l+r)>>1;
    build(t[x].chl,l,mid); build(t[x].chr,mid+1,r);
}
void insert(int &x,int rot,int key,int flag,ll val,int l,int r) 
{
    x=++tot;
    t[x].chl=t[rot].chl;
    t[x].chr=t[rot].chr;
    t[x].cnt=t[rot].cnt+flag;
    t[x].val=t[rot].val + flag*val;
    if (l==r) {
        return ;
    }
    int mid=(l+r)>>1;
    if (key>mid) {
        insert(t[x].chr,t[rot].chr,key,flag,val,mid+1,r);
    } else {
        insert(t[x].chl,t[rot].chl,key,flag,val,l,mid);
    }
}
ll query(int a,int l,int r,int k)
{
    if(t[a].cnt<=k)return t[a].val;
    if(l==r)
    {
        if(t[a].cnt>k)
        {
            return (ll)(t[a].val/t[a].cnt)*k;
        }
        else return 0;
    }
    int mid = (l+r)>>1;
    if(k<=t[t[a].chl].cnt)return query(t[a].chl,l,mid,k);
    else  
    {
        return t[t[a].chl].val + query(t[a].chr,mid+1,r,k - t[t[a].chl].cnt);
    }
}
int main()
{
    while(~scanf("%d%d%d%lld",&n,&m,&X,&p))
    {
        mp.clear();
        int l,r,d;
        int cnt = 0;
        int cntd = 0;
        for(int i = 0;i<n;i++)
        {
            scanf("%d%d%d",&l,&r,&d);
            r++;
            if(!mp[d])
            {
                mp[d] = 1;
                dis[cntd++] = d;
            }
            tag_point[cnt].x = l;
            tag_point[cnt].d = d;
            tag_point[cnt++].flag = 1;
            tag_point[cnt].x = r;
            tag_point[cnt].d = d;
            tag_point[cnt++].flag = -1;
        }
        sort(tag_point,tag_point+cnt);
        sort(dis,dis+cntd);
        tot = 0;
        build(root[0],1,cntd);
        for(int i = 0;i<cnt;i++)
        {
            int hash_d = lower_bound(dis,dis+cntd,tag_point[i].d)-dis+1;
            insert(root[i+1],root[i],hash_d,tag_point[i].flag,tag_point[i].d,1,cntd);
        }
        int x;
        ll a,b,c;
        ll pre = 1;
        int k;
        ll ans;
        while(m--)
        {
            scanf("%d%lld%lld%lld",&x,&a,&b,&c);
            k = ((a*pre)%c+b)%c;
            if(!k)ans = 0;
            else
            {
                pnode tmp;
                tmp.x = x;
                tmp.d = inf;
                tmp.flag = 0;
                int id = upper_bound(tag_point,tag_point+cnt,tmp) - tag_point;
                if(id==0)ans = 0;
                else ans = query(root[id],1,cntd,k);
            }
            if(pre>p)ans*=2;
            printf("%lld\n",ans);
            pre = ans;
        }
    }
}   

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值