[ABC340E] Mancala 2
线段树板题,为了方便,从 开始标号。
直接考虑每次操作,每个人的排位构成一个环,就是把当前的人的球拿走,然后不断往后传,传到谁谁拿一个,传完就结束。
因为 很大,我们不能直接模拟传球的过程,所以不妨直接计算能传多少轮(也就是走一圈回到当前点),然后对余数 进行一个处理。
如果当前位置加一往后到 的位置数量大于 的话,那直接对这段区间修改即可。
否则拆成两段,从当前位置加一到 ,以及从 到剩下部分修改。
#include<bits/stdc++.h>
using namespace std;
const int N =1e6+10;
#define int long long
struct node{
int sum,lazy;
}d[N<<1];
int a[N],n,m;
void build(int s,int t,int p){
if(s==t){
d[p].sum=a[s];
return ;
}
int mid=(s+t)>>1;
build(s,mid,p<<1),build(mid+1,t,p<<1|1);
d[p].sum=d[p<<1|1].sum+d[p<<1].sum;
}
void push_down(int s,int t,int p){
int mid=(s+t)>>1;
d[p<<1].sum+=(mid-s+1)*d[p].lazy,d[p<<1].lazy+=d[p].lazy;
d[p<<1|1].sum+=(t-mid)*d[p].lazy,d[p<<1|1].lazy+=d[p].lazy;
d[p].lazy=0;
}
void update(int l,int r,int s,int t,int p,int change){
if(l<=s&&t<=r){
d[p].sum+=(t-s+1)*change,d[p].lazy+=change;
return ;
}
int mid=(s+t)>>1;
push_down(s,t,p);
if(l<=mid) update(l,r,s,mid,p<<1,change);
if(r>mid) update(l,r,mid+1,t,p<<1|1,change);
d[p].sum=d[p<<1|1].sum+d[p<<1].sum;
}
int Query(int l,int r,int s,int t,int p){
if(l<=s&&t<=r) return d[p].sum;
int mid=(s+t)>>1,ans=0;
push_down(s,t,p);
if(l<=mid) ans+=Query(l,r,s,mid,p<<1);
if(r>mid) ans+=Query(l,r,mid+1,t,p<<1|1);
return ans;
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
build(1,n,1);
for(int i=1,x;i<=m;i++){
cin>>x,x++;
int now=Query(x,x,1,n,1),pre=now/n;
update(x,x,1,n,1,-now),update(1,n,1,n,1,pre);
int lst=now-pre*n;
if(x+1+lst-1<=n&&lst!=0)
update(x+1,x+1+lst-1,1,n,1,1);
else{
if(x!=n&&lst!=0) update(x+1,n,1,n,1,1);
if(lst!=0) update(1,lst-(n-(x+1)+1),1,n,1,1);
}
}
for(int i=1;i<=n;i++) cout<<Query(i,i,1,n,1)<<" ";
cout<<endl;
}

浙公网安备 33010602011771号