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;
}
少女が見た日本の原風景