zoukankan      html  css  js  c++  java
  • ARC068E

    原题链接

    题意简述

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

    题解

    考虑怎样的区间不包含k的倍数。
    对于k的倍数tktk+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);
        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
    ",ans);
        }
        return 0;
    }

    注意

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

  • 相关阅读:
    面向对象
    linux下apache重启报错
    mysql登录密码忘记怎么办?
    html基础知识梳理
    用js实现贪吃蛇
    简单轮播图案例
    JavaScript基础学习笔记整理
    读书笔记之《Redis开发与运维》—— 三
    读书笔记之《Redis开发与运维》—— 二
    读书笔记之《Redis开发与运维》—— 一
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485759.html
Copyright © 2011-2022 走看看