正题
题目链接:https://www.luogu.com.cn/problem/P3527
题目大意
mmm个格子形成的环,有nnn个集合,第iii个格子属于第oio_ioi个集合,kkk次让环上一段的格子加上一个权值。
对于每个iii求出第iii个集合在多少次的时候它集合中的所有格子权值和大于pip_ipi
解题思路
单个的时候可以二分做,多个的时候就一起二分做。
对于每次二分的区域[L,R][L,R][L,R]就把[L,mid][L,mid][L,mid]操作给做了,然后判断目前集合内满足条件的丢到左边,不满足的丢到右边继续分治下去。
用树状数组维护区间和就好统计了,像CDQCDQCDQ分治一样注意做完左边不需要清空影响,留到右边作为信息。
环形的话一个操作拆成两个就好了。
时间复杂度O(nlog2n)O(n\log^2 n)O(nlog2n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define lowbit(x) (x&-x)
#define ll long long
using namespace std;
const ll N=3e5+10;
struct node{ll l,r,w;
}q[N];
ll n,m,k,p[N],p1[N],p2[N],t[N],ans[N],lim[N];
vector<ll> v[N];
void Change(ll x,ll val){while(x<=m){t[x]+=val;x+=lowbit(x);}return;
}
ll Ask(ll x){ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
void solve(ll L,ll R,ll l,ll r){if(L==R){for(ll i=l;i<=r;i++)ans[p[i]]=L;ll i=L;if(q[i].l<=q[i].r)Change(q[i].l,q[i].w),Change(q[i].r+1,-q[i].w);elseChange(q[i].l,q[i].w),Change(1,q[i].w),Change(q[i].r+1,-q[i].w);return;}ll mid=(L+R)>>1;for(ll i=L;i<=mid;i++){if(q[i].l<=q[i].r)Change(q[i].l,q[i].w),Change(q[i].r+1,-q[i].w);elseChange(q[i].l,q[i].w),Change(1,q[i].w),Change(q[i].r+1,-q[i].w);}ll cnt1=0,cnt2=0;for(ll i=l;i<=r;i++){ll x=p[i],w=0;for(ll j=0;j<v[x].size();j++){w+=Ask(v[x][j]);if(w>=lim[x])break;}if(w>=lim[x])p1[++cnt1]=x;else p2[++cnt2]=x;}ll cnt=l-1;for(ll i=1;i<=cnt1;i++)p[++cnt]=p1[i];for(ll i=1;i<=cnt2;i++)p[++cnt]=p2[i];for(ll i=L;i<=mid;i++){if(q[i].l<=q[i].r)Change(q[i].l,-q[i].w),Change(q[i].r+1,q[i].w);elseChange(q[i].l,-q[i].w),Change(1,-q[i].w),Change(q[i].r+1,q[i].w);}solve(L,mid,l,r-cnt2);solve(mid+1,R,l+cnt1,r);return;
}
signed main()
{scanf("%lld%lld",&n,&m);for(ll i=1;i<=m;i++){ll x;scanf("%lld",&x);v[x].push_back(i);}for(ll i=1;i<=n;i++)scanf("%lld",&lim[i]),p[i]=i;scanf("%lld",&k);for(ll i=1;i<=k;i++)scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].w);q[++k]=(node){1,n,(ll )1e9+7};solve(1,k,1,n);for(ll i=1;i<=n;i++){if(ans[i]<k)printf("%lld\n",ans[i]);else printf("NIE\n");}return 0;
}