gym102452 I Incoming Asteroids (2019-2020 ICPC Asia Hong Kong Regional Contest) 抽屉原理
题意
有\(n\)个位置可以进行观测。第一种操作可以在\(k\ (k\le3)\)个位置添加摄像头,目标是收集\(y\)个单位的观测值;第二种操作是在第\(x\)个位置所有的摄像头产生了\(y\)个单位的观测值,输出该次操作使得操作一首次达到目标的数量和编号。强制在线。
思路
考虑\(k\)的值比较少,并由抽屉原理,我们可以对每个位置建立一个数据结构,插入操作一目标的\(\frac1k\),当这个位置的观测值的增长超过插入值时,取出并更新操作一的目标并重新插入。这样每次取出操作一的目标至少减少到原来的\(\frac{k-1}k\),对于每个操作一最多取出\(log_{\frac{k-1}k}(y)\)次,总复杂度\(O(m*log\ m*log\ y)\)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
#define mp make_pair
const int maxn=2e5+5;
const int maxm=2e5+5;
ll v[maxn];
priority_queue<pli,vector<pli>,greater<pli> >st[maxn];
int Q[maxm][4];
int Y[maxm],D[maxm];
int vis[maxm];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int op,x,k,q,last=0,cnt=0;
ll y;
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%lld%d",&y,&k);
y=y^last;
++cnt;
Q[cnt][0]=k;
Y[cnt]=D[cnt]=y;
for(int kk=1;kk<=k;kk++)
{
scanf("%d",&q);
q=q^last;
Q[cnt][kk]=q;
Y[cnt]+=v[q];
}
for(int kk=1;kk<=k;kk++)
st[Q[cnt][kk]].push(mp(v[Q[cnt][kk]]+(D[cnt]+k-1)/k,cnt));
}
else //op==2
{
scanf("%d%d",&x,&y);
x=x^last;
y=y^last;
vector<int>ans;
v[x]+=y;
while(!st[x].empty() && st[x].top().first<=v[x])
{
ll tmp=st[x].top().first;
int i=st[x].top().second;
st[x].pop();
if(vis[i])continue;
D[i]=Y[i];
for(int kk=1;kk<=Q[i][0];kk++)
D[i]-=v[Q[i][kk]];
if(D[i]<=0)
{
ans.push_back(i);
vis[i]=1;
}
else
{
k=Q[i][0];
for(int kk=1;kk<=k;kk++)
st[Q[i][kk]].push(mp(v[Q[i][kk]]+(D[i]+k-1)/k,i));
}
}
sort(ans.begin(),ans.end());
printf("%d",last=(int)ans.size());
for(int i=0;i<ans.size();i++)
printf(" %d",ans[i]);
printf("\n");
}
}
return 0;
}