ARC068E Snuke Line

Link
假设现在枚举的列车是隔\(d\)站停一次车。
那么对于所有长度\(\ge d\)的区间,一定会在这个区间中停至少一次车。
对于所有长度\(<d\)的区间,最多在这个区间中停一次车。
因此我们可以先把所有区间按区间长度升序排序,然后从小到大枚举停车间隔\(d\),把所有区间长度\(=d-1\)的加进树状数组,然后枚举倍数查询总共停了多少个区间,再加上所有\(\ge d\)的区间个数就行了。

#include<cstdio>
#include<cctype>
#include<algorithm>
const int N=300007,M=100007;
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
struct node{int l,r;}a[N];
int n,m,ans[M],t[M];
void add(int p,int v){for(;p<=m;p+=p&-p)t[p]+=v;}
void upd(int l,int r){add(l,1);if(r<m)add(r+1,-1);}
int ask(int p){int s=0;for(;p;p^=p&-p)s+=t[p];return s;}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i) a[i].l=read(),a[i].r=read();
    std::sort(a+1,a+n+1,[](node&a,node&b){return a.r-a.l<b.r-b.l;});
    for(int i=1,p=1,s;i<=m;++i)
    {
    for(s=0;p<=n&&a[p].r-a[p].l<i;++p) upd(a[p].l,a[p].r);
    for(int j=i;j<=m;j+=i) s+=ask(j);
    printf("%d\n",n-p+1+s);
    }
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/12193770.html