1. 程式人生 > >AtCoder Regular Contest 068E:Snuke Line

AtCoder Regular Contest 068E:Snuke Line

題目傳送門:https://arc068.contest.atcoder.jp/tasks/arc068_c

題目翻譯

直線上有\(0~m\)\(m+1\)個點,一共有\(m\)輛火車。第\(i\)輛火車只會在\(i\)的倍數點上停靠,所有車都從\(0\)號點出發。

一共有\(n\)個商品,第\(i\)個商品只會在\(l_i~r_i\)號點出售,問你對於每輛火車,在可以停靠的站裡,可以買到的商品種類數。

\(m\leqslant 10^5,n\leqslant 3*10^5\)

題解

對於長度大於等於\(i\)的區間,肯定會對\(i\)號火車有貢獻。長度小於\(i\)的,我們用樹狀陣列差分查詢就行了。

因為所有站點總和為\(mlogm\),所以時間複雜度為\(mlog^2m\)

時間複雜度: \(O(mlog^2m)\)

空間複雜度:\(O(m)\)

程式碼如下:

#include <cstdio>
#include <vector>
using namespace std;
#define low(i) ((i)&(-(i)))
 
const int maxm=1e5+5;
 
int n,m,cnt;
vector<int>range[maxm];
vector<int>::iterator it;
 
int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}
 
struct TreeArray {
    int c[maxm];
 
    void change(int pos,int v) {
        for(int i=pos;i<=m;i+=low(i))
            c[i]+=v;
    }
 
    int query(int pos) {
        int res=0;
        for(int i=pos;i;i-=low(i))
            res+=c[i];
        return res;
    }
}T;
 
int main() {
    cnt=n=read(),m=read();
    for(int i=1;i<=n;i++) {
        int l=read(),r=read();
        range[r-l+1].push_back(l);
    }
    for(int i=1;i<=m;i++) {
        int ans=cnt;
        for(int pos=i;pos<=m;pos+=i)
            ans+=T.query(pos);
        for(it=range[i].begin();it!=range[i].end();it++)
            T.change(*it,1),T.change((*it)+i,-1),cnt--;
        printf("%d\n",ans);
    }
    return 0;
}