1. 程式人生 > 其它 >P3674 小清新人渣的本願(莫隊+bitset)

P3674 小清新人渣的本願(莫隊+bitset)

目錄

Description

給你一個序列 aa,長度為 nn,有 mm 次操作,每次詢問一個區間是否可以選出兩個數它們的差為 xx,或者詢問一個區間是否可以選出兩個數它們的和為 xx,或者詢問一個區間是否可以選出兩個數它們的乘積為 xx ,這三個操作分別為操作 1,2,31,2,3

選出的這兩個數可以是同一個位置的數。

State

\(n, m, max(x, a[i])<=10^5\)
\(a[i]>=0, x >= 2\)

Input

​ 5 5
1 1 2 3 4
2 1 1 2
1 1 2 2
3 1 1 1
3 5 5 16
1 2 3 4

Output

​ hana
bi
hana
hana
bi

Solution

看到題目的第一眼感覺用一個數組覺可以解決,但是題目設計的比較妙


如果上一次是 \(1\) 操作,當前為 \(2\) 操作,區間都相同,那麼該怎麼辦呢

這提示我們需要用一種複雜度極低的查詢方式,可以利用 \(bitset\) 的與操作

  1. \(bitset & (bitset << x)\)
    查詢新的集合中是否存在 \(1\)
  2. \(a+b=x\) 其中 \(a,b\) 是在 \(bitset\) 中出現過的數,將起轉化為\(N-a-b=N-x\),也就是 \((N-b)-a=(N-x)\),這樣又變成了 \(1\) 的形式
  3. 這個就比較套路了,列舉 \(x\) 的因子就可以了

Code

const int N = 1e5 + 5;
 
    int n, m;
    int a[N];
    struct Query
    {
        int l, r;
        int bel;
        int id, opt, x;
        bool operator<(Query o){
            return bel == o.bel ? r < o.r: l < o.l;
        }
        void read(){ 
            sd(opt), sdd(l, r), sd(x); 
        }
    }q[N];
    int block, vis[N];
    bool ans[N];
    bitset<N> now, rev;

void mo()
{
    block = 3 * sqrt(n);
    for(int i = 1; i <= m; i ++){
        q[i].id = i;
        q[i].bel = q[i].l / block + 1;
    }
    sort(q + 1, q + 1 + m);
}

void add(int pos)
{
    int x = a[pos];
    vis[x] ++;
    now[x] = 1;
    rev[N - x] = 1; 
}

void del(int pos)
{
    int x = a[pos];
    vis[x] --;
    if(vis[x]) return ;
    now[x] = 0;
    rev[N - x] = 0;
}

signed main()
{
    while(~ sdd(n, m)){
        rep(i, 1, n) sd(a[i]);
        rep(i, 1, m) q[i].read();
        mo();
        int l = 1, r = 0;
        now = 0;
        rev = 0;
        for(int i = 1; i <= m; i ++){
            while(l > q[i].l) add(-- l);
            while(r < q[i].r) add(++ r);
            while(l < q[i].l) del(l ++);
            while(r > q[i].r) del(r --);
            // dbg(now[1]);
            if(q[i].opt == 1){
                ans[q[i].id] = ((now & (now << q[i].x))).any();
            }
            else if(q[i].opt == 2){
                ans[q[i].id] = ((rev & (now << N - q[i].x)).any());
            }
            else{
                for(int k = 1; k * k <= q[i].x; k ++){
                    if(q[i].x % k == 0 && now[k] && now[q[i].x / k]){
                        ans[q[i].id] = 1;
                        break;
                    }
                }
            }
        }
        rep(i, 1, m) puts(ans[i]? "hana": "bi");
    }
    return 0;
}