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);
    }
}
posted @ 2021-10-07 15:32  Kreap  阅读(39)  评论(0编辑  收藏  举报