CF1580C Train Maintenance
Description
\(m\) 个车,每个车从第 \(s_i\) 天开始,运行 \(x_i\) 天,然后维修 \(y_i\) 天,这样循环,直到第 \(t_i\) 天的时候结束。对于每一天,输出当天正在维修的车的数量。
Solution
考场上都想到正解了,但是想错了以为 \(m\) 是 2e5(其实只有 1e5),很卡常,就没写,服了……
和哈希冲突很像,考虑根号分治。对于 \(x+y\leq \sqrt m\) 的,直接暴力跳位置打差分标记。对于大于 \(\sqrt m\) 的,由于每一段很短,所以可以维护一个数组 \(f[w][i]\) 表示对 \(t=kw+i\) 的位置打上标记,然后这个就可以实时暴力更新。
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
const int sqN=5e2;
const int N=2e5+7;
int f[sqN][sqN],lt[N],q[N],tag[N];
int x[N],y[N];
int main(){
int n=read(),m=read();
int sq=(int)(sqrt(m)+0.5);
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=1;i<=m;i++){
int op=read(); q[i]=read();
int w=x[q[i]]+y[q[i]];
if(w>sq){
if(op==1) lt[q[i]]=i;
else{
for(int j=lt[q[i]]+x[q[i]];j<=i;j+=w)
tag[j]++,tag[min(i,j+y[q[i]])]--;
lt[q[i]]=0;
}
}
}
for(int i=1;i<=n;i++)
if(lt[i]){
int w=x[i]+y[i];
for(int j=lt[i]+x[i];j<=m;j+=w)
tag[j]++,tag[min(m+1,j+y[i])]--;
}
int now=0;
for(int i=1;i<=m;i++){
int w=x[q[i]]+y[q[i]];
now+=tag[i];
if(w<=sq){
if(!lt[q[i]]){
for(int j=x[q[i]];j<w;j++)
f[w][(i+j)%w]++;
lt[q[i]]=i;
}else{
for(int j=x[q[i]];j<w;j++)
f[w][(lt[q[i]]+j)%w]--;
lt[q[i]]=0;
}
}
int ans=now;
for(int j=1;j<=sq;j++) ans+=f[j][i%j];
printf("%d\n",ans);
}
}