ARC068E - Snuke Line

原题链接

题意简述

给出 n(n3×105) 个区间和 m(m105) 。求对于任意 km ,有多少个区间包含 k 的倍数。

题解

考虑怎样的区间不包含k的倍数。
对于 k 的倍数tk tk+k ,满足 L,R(tk,tk+k) 的区间 [L,R] 不包含任何 k 的倍数。
于是转化为二维数点问题,可以用可持久化线段树解决。把区间[L,R]视作一个横坐标为 L ,纵坐标为R的点,则 L,R(tk,tk+k) 等价于点 (L,R) 在矩形 (tk,tk)(tk+k,tk+k) 内部。
时间复杂度 O(nlogm+mi=1mi×logm)=O(nlogm+mlog2m)

Code

//Snuke Line
#include <cstdio>
#include <algorithm>
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
int const N=3e5+10;
int const M=1e5+10;
int n,m;
struct range{int fr,to;} rg[N];
bool cmpRg(range x,range y) {return x.fr<y.fr;}
int sgCnt,rt[M];
struct seg{int cnt; int L,R;} sg[N*20];
void update(int s) {sg[s].cnt=sg[sg[s].L].cnt+sg[sg[s].R].cnt;}
void ins(int &s,int fr,int to,int x)
{
    sg[++sgCnt]=sg[s]; s=sgCnt;
    if(fr==to) {sg[s].cnt++; return;} 
    int mid=fr+to>>1;
    if(x<=mid) ins(sg[s].L,fr,mid,x);
    else ins(sg[s].R,mid+1,to,x);
    update(s);
}
int query(int s1,int s2,int fr,int to,int fr0,int to0)
{
    if(fr0<=fr&&to<=to0) return sg[s2].cnt-sg[s1].cnt;
    int mid=fr+to>>1; int res=0;
    if(fr0<=mid) res+=query(sg[s1].L,sg[s2].L,fr,mid,fr0,to0);
    if(mid<to0) res+=query(sg[s1].R,sg[s2].R,mid+1,to,fr0,to0);
    return res;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++) rg[i].fr=read(),rg[i].to=read();
    std::sort(rg+1,rg+n+1,cmpRg);
    rt[0]=0; int p=1;
    for(int i=1;i<=m;i++)
    {
        rt[i]=rt[i-1];
        while(rg[p].fr==i) ins(rt[i],1,m,rg[p].to),++p;
    }
    printf("%d\n",n);
    for(int d=2;d<=m;d++)
    {
        int ans=n,i;
        for(i=d;i<=m;i+=d) ans-=query(rt[i-d],rt[i-1],1,m,i-d+1,i-1);
        if(i-d+1<=m) ans-=query(rt[i-d],rt[m],1,m,i-d+1,m);
        printf("%d\n",ans);
    }
    return 0;
}

注意

空间复杂度为 O(nlogm) ,因为对于每个点(每个区间)都要建一个 O(logm) 的线段树。
对于有些 k <script type="math/tex" id="MathJax-Element-2380">k</script>最后会有剩余,所以有if(i-d+1<=m) ans-=query(rt[i-d],rt[m],1,m,i-d+1,m);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值