ZOJ-3453:Doraemon's Sweet Bullet

Doraemon likes to shoot his enemies with sweet bullets.

n "enemies" stand in a line, each with a life value li (the index i increases from left to right side and starts from 1). Each time Doraemon shoots a sweet bullet from the right side. The ith bullet has a "critical range" ki. That is to say, it attacks the first enemy from right side whose life value is equal to or greater than ki. The life value of the attacked enemy will decrease to 1 immediately.

However, Doraemon finds a terrible fact that after an enemy is attacked, it will distribute the sweets to his friends and his friends' life value will increase by 1. For the ith enemy, his friends are in a consecutive range from the aith enemy to the bith. Note that an enemy may be the friend of himself so that after being attacked his life value will be 2.

What's more, if a bullet can't find a target--there doesn't exist an enemy with life greater or equal than ki, all enemies' life will increase by 1.

Now Doraemon wants to know after m bullets were shot, what the maximum life value in all enemies is.

Input

The input contains multiple test cases.

Each test case begins with a line containing a single integer n (1 ≤ n ≤ 100000) indicating the number of enemies.

The following n lines describes enemies, one enemy each line. Each line contains three integers, the initial life value li (1 ≤ li ≤ 10000) and his range of friends ai bi (1 ≤ ai ≤ bi≤ n) - that is, enemies with index from ai to bi(inclusive) are all his friends.

The following line contains an integer m (1 ≤ m ≤ 100000) indicating the number of bullets Doraemon has shot. The last m lines follows, each with a single integer ki(1 ≤ ki ≤ 10000) describing the bullet's "critical range".

Different cases are separated by a blank line.

Process to the end of input.

Output

For each test case, output the maximum life value after shooting in a single line.

Sample Input
3
3 1 2
4 1 3
5 1 1
3
4
2
1
Sample Output
6
Hint

Doraemon suggests that you should use scanf to read data.



思路:典型的线段树区间更新和单点查找。每次找比k大的值的时候,尽可能的往右子树查找就行了。


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX=1e5+10;
struct data
{
    int HP,l,r;
}b[MAX];
struct lenka
{
    int l,r,HP;
    int tag;
}a[MAX<<2];
void build(int k,int l,int r)
{
    a[k].l=l,a[k].r=r;
    a[k].tag=0;
    if(l==r){a[k].HP=b[l].HP;return;}
    build(2*k,l,(l+r)/2);
    build(2*k+1,(l+r)/2+1,r);
    a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
}
void change(int k,int l,int r,int tag)
{
    if(a[k].l==l&&a[k].r==r)
    {
        a[k].HP+=tag;
        a[k].tag+=tag;
        return;
    }
    if(a[k].tag&&a[k].l!=a[k].r)
    {
        change(2*k,a[2*k].l,a[2*k].r,a[k].tag);
        change(2*k+1,a[2*k+1].l,a[2*k+1].r,a[k].tag);
        a[k].tag=0;
        a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
    }
    if(r<=a[2*k].r)change(2*k,l,r,tag);
    else if(l>=a[2*k+1].l)change(2*k+1,l,r,tag);
    else change(2*k,l,a[2*k].r,tag),change(2*k+1,a[2*k+1].l,r,tag);
    a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
}
int ask(int k,int x)
{
    //printf("%d (%d,%d) HP=%d\n",k,a[k].l,a[k].r,a[k].HP);
    if(a[k].tag&&a[k].l!=a[k].r)
    {
        change(2*k,a[2*k].l,a[2*k].r,a[k].tag);
        change(2*k+1,a[2*k+1].l,a[2*k+1].r,a[k].tag);
        a[k].tag=0;
        a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
    }
    if(a[k].HP<x)return -1;
    if(a[k].HP>=x&&a[k].l==a[k].r)
    {
        a[k].HP=1;
        return a[k].l;
    }
    int ans;
    if(x<=a[2*k+1].HP)ans=ask(2*k+1,x);
    else if(x<=a[2*k].HP)ans=ask(2*k,x);
    else return -1;
    a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
    return ans;
}
void update(int k)
{
    if(a[k].l==a[k].r)return;
    if(a[k].tag)
    {
        change(2*k,a[2*k].l,a[2*k].r,a[k].tag);
        change(2*k+1,a[2*k+1].l,a[2*k+1].r,a[k].tag);
        a[k].tag=0;
        a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
    }
    update(2*k);
    update(2*k+1);
    a[k].HP=max(a[2*k].HP,a[2*k+1].HP);
}
int main()
{
    int n,T;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)scanf("%d%d%d",&b[i].HP,&b[i].l,&b[i].r);
        build(1,1,n);
        scanf("%d",&T);
        while(T--)
        {
            int x;
            scanf("%d",&x);
            x=ask(1,x);
            if(x!=-1)change(1,b[x].l,b[x].r,1);
            else change(1,1,n,1);
        }
        update(1);    //最后在更新一下
        cout<<a[1].HP<<endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值