題意
有\(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;
}