codeforces975C 题解

题意

有从前到后排列的n个勇士,第i回合射出ki发箭,一共射q回合,每一次射箭会射到当前在头上还未倒下的勇士,勇士i被射中ai次之后会倒下,所有勇士都倒下之后会在本回合内复活。

笺释

其实这道题算是一道相当标准(简单)的cf数据结构题,但是自己也是菜,上来就奔着模拟去了,写了个线段树,还一直wa。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL long long
#define MAXN 300005
const int maxn = 1000005;
using namespace std;
int n,q;
long long qi;
long long a[maxn];
LL lazy[maxn<<2];
LL sum[maxn<<2];
void PushUp(int rt)//由左孩子、右孩子向上更新父节点
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void PushDown(int rt,int m) //向下更新
{
    if (lazy[rt]!=-1) //懒惰标记
    {
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        sum[rt<<1] = (m - (m >> 1)) * lazy[rt];
        sum[rt<<1|1] = ((m >> 1)) * lazy[rt];
        lazy[rt] = -1;
    }
}
void build(int l,int r,int rt)//建树
{
    lazy[rt] = -1;

    if (l== r)
    {
        sum[rt]=a[l];
        //printf("%d %d\n",rt,sum[rt]);
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void update(int L,int R,long long c,int l,int r,int rt)//更新
{
    //if(L>l||R>r) return;
    if (L <= l && r <= R)
    {
        lazy[rt] = c;
        sum[rt] = c * (r - l + 1);
        return ;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if (L <= m) update(L , R , c , lson);
    if (R > m) update(L , R , c , rson);
    PushUp(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        //printf("%d\n", sum[rt]);
        return sum[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    LL ret = 0;
    if (L <= m) ret += query(L , R , lson);
    if (m < R) ret += query(L , R , rson);
    return ret;
}
int check(int x)
{
    if(query(1,x,1,n,1)<=qi)
    {
        return 0;
    }
    return 1;
}
void update1(int p,long long tihuan,int l,int r,int rt)
{
    if (l == r) {
        sum[rt] = tihuan;
        return ;
    }
    int m = (l + r) >> 1;
    if (p <= m) update1(p , tihuan ,lson);
    else update1(p , tihuan , rson);
    PushUp(rt);
}
int solve(int flag)
{
    if(query(1,n,1,n,1)<=qi)
    {
        build(1,n,1);
        return n;
    }
    int l=1,r=n,ans=-1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
       // printf("%d\n",mid);
        if(check(mid))
        {
            r=mid-1;
        }
        else
        {
            l=mid+1;
        }
    }
        long long tem=(qi-query(1,l,1,n,1));
        update1(l,-tem,1,n,1);
        //printf("B %d\n",tem);
        if(l>=2)
        {
            update(1,l-1,0,1,n,1);
        }
        return n-(l-1);
}
int main()
{
    scanf("%d %d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    int flag=1;
    build(1,n,1);
    while(q--)
    {
        scanf("%lld",&qi);
        printf("%d\n",solve(flag++));
    }
    return 0;
}

在第六个点wa了好久,后来才发现是因为我的区间修改lazy数组是用if(lazy[rt])更新的,也就是说如果lazy[rt]==0是不会更新的,但是lazy[rt]确实是我们要更新的状态=。=
然后改了之后变成在第8个点tle了,线段树就算是无计可施了。
仔细想想,其实这道题和codefroces948c是很像的,如果把雪堆看成勇士的话,二者都是每一回合削减某些,并且想要获取当前回合的信息。
如果设a[i]为第1-i个勇士的总生命值,d[i]为1-i回合的总箭量,显然,在1-i名勇士中做一个二分搜索即可,然后又因为所有勇士都倒下后会复活,那么如果搜索到的是勇士的末尾,就重置d。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,q;
ll a[N],k[N];
int main()
{
    int i,j;
    ll d;
    scanf("%d%d",&n,&q);
    for(i=0;i<n;i++) scanf("%I64d",a+i);
    for(i=0;i<q;i++) scanf("%I64d",k+i);
    for(i=1;i<n;i++) a[i]+=a[i-1];
    d=0;
    for(i=0;i<q;i++){
        d+=k[i];
        j=upper_bound(a,a+n,d)-a;
        if(j==n) d=j=0;
        printf("%d\n",n-j);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/SoniciSika/p/8983602.html