CF1580C Train Maintenance

Description

(m) 个车,每个车从第 (s_i) 天开始,运行 (x_i) 天,然后维修 (y_i) 天,这样循环,直到第 (t_i) 天的时候结束。对于每一天,输出当天正在维修的车的数量。

Solution

考场上都想到正解了,但是想错了以为 (m) 是 2e5(其实只有 1e5),很卡常,就没写,服了……

和哈希冲突很像,考虑根号分治。对于 (x+yleq 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
",ans);
    }
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/15376070.html