正题
题目大意
有nnn个数字开始都是000,要求有qqq次操作。
- 新建一个观测员,观测其中的kkk个数,当这kkk个数从此刻开始变化量不小于ttt时观测结束。
- 将第iii个数加vvv,并输出此时观测结束的观测员编号。
强制在线
1≤n,q≤2×105,1≤k≤3,1≤t,v≤1061\leq n,q\leq 2\times 10^5,1\leq k\leq 3,1\leq t,v\leq 10^61≤n,q≤2×105,1≤k≤3,1≤t,v≤106
解题思路
考虑从kkk入手,根据鸽笼原理,一个观测员观测结束当且仅当存在它观测的一个数字a≥⌈tk⌉a\geq \lceil\frac{t}{k}\rceila≥⌈kt⌉,注意到此时已经至少填充了⌈tk⌉\lceil\frac{t}{k}\rceil⌈kt⌉。
所以我们可以对于每个它观测的数字以⌈tk⌉\lceil\frac{t}{k}\rceil⌈kt⌉为界,当到倒打这个界时,我们直接重新根据现在的数字再来一次,也就是把ttt剩余的部分再分成kkk份丢回去。
一直这样做知道合法为止,此时每次会至少令t=k−1ktt=\frac{k-1}{k}tt=kk−1t,所以这样的次数应该为logkk−1t\log_{\frac{k}{k-1}}tlogk−1kt。
用个setsetset维护就好了,时间复杂度:O(qlogkk−1tklogq)O(q\log_{\frac{k}{k-1}}tk\log q)O(qlogk−1ktklogq)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<cmath>
#define ll long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const ll N=2e5+10;
ll n,m,cnt,a[N],t[N];
vector<ll> ans,q[N],c[N];
set<pair<ll,ll> >s[N];
void update(ll x){ll sum=0;for(ll i=0;i<q[x].size();i++){ll y=q[x][i];sum+=a[y];s[y].erase(mp(c[x][i],x));}if(sum>=t[x])ans.push_back(x);else{for(ll i=0;i<q[x].size();i++){ll y=q[x][i];c[x][i]=a[y]+ceil((double)(t[x]-sum)/q[x].size());s[y].insert(mp(c[x][i],x));}}return;
}
signed main()
{
// freopen("obs.in","r",stdin);
// freopen("obs.out","w",stdout);scanf("%lld%lld",&n,&m);ll las=0;while(m--){ll op;scanf("%lld",&op);if(op==1){ll k,sum=0;++cnt;scanf("%lld%lld",&t[cnt],&k);t[cnt]^=las;for(ll i=0,x;i<k;i++){scanf("%lld",&x);x^=las;q[cnt].push_back(x);sum+=a[x];c[cnt].push_back(a[x]+ceil((double)t[cnt]/k));s[x].insert(mp(c[cnt][i],cnt));}t[cnt]+=sum;}else{ans.clear();ll p,w;scanf("%lld%lld",&p,&w);p^=las;w^=las;a[p]+=w;while(!s[p].empty()){pair<ll,ll> k=*s[p].begin();if(a[p]>=k.first)update(k.second);else break;}printf("%lld",las=ans.size());sort(ans.begin(),ans.end());for(ll i=0;i<ans.size();i++)printf(" %lld",ans[i]);putchar('\n');}}return 0;
}