LoginSignup
0
0

More than 3 years have passed since last update.

セグ bit

Last updated at Posted at 2020-04-29

そろそろやらないと無理な気がしてきたので
セグ木
何ができるか?
数列a0,,,,an-1があるとき次の二つの処理をo(logn)で実現することを目指す
1,s,tが与えられた時as,,,,atの最小値を求める
2,i,xが与えられた時aiの値をxnに変更する
各節点では対応する区間の最小値を持つようにする

rmqの実装例

//値を更新する際は子ノードから親ノードへと辿りながら更新していく下から上へ区間で受け止める感じ
//ある区間の最小値を知りたい際は親ノードから子ノードへと辿りながら値を更新していく上から下へ
//葉はn個の数列に対応するので全体としては2*n-1個のノードで表すことができる配列のサイズは2*n-1
//dat[2*n-1]で表す
//親から子へのアクセスは左の子:dat[2*i+1],右の子:dat[2*i+2]
//子から親へのアクセスは親:dat[(i-1)/2]

#define MAX_INF 2147483647
int n;
vector<int>value;
//Nは葉の数datはノードの値を持つ配列
//k番目の値をaに変更
void update(int k, int a) {
    //i番目の葉の値をxに変える
    k += n - 1;//i番目の葉のノード番号
    value[k] = a;
    while (k > 0) {
        k = (k - 1) / 2;//ノードiのノードの便号に変える
        value[k] = min(value[k * 2 + 1], value[k * 2 + 2]);
    }
}
//[a,b)の最小値を求める
//後ろのほうの引数は計算の簡単のための引数
//kは節点の番号、l,rはその節点が[l,r)に対応づいていることを表す
//従って外からはquery(a,b,0,0,n)として呼ぶ
int query(int a, int b, int k, int l, int r) {
    //[a,b)と[l,r)が交差しなければINT_MAX
    if (r <= a || b <= l)return MAX_INF;
    //[a,b)が[l,r)を完全に含んでいればこの節点の値
    if (a <= l && r <= b)return value[k];
    else {
        //そうでなければ二つの子の最小値
        int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);//左の子に値を聞く
        int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);//右の子に値を聞く
        return min(vl, vr);
    }
}
int main() {
    int N, Q; cin >> N >> Q;
    n = 1;
    while (n < N)n *= 2;
    value = vector<int>(2 * n - 1, MAX_INF);
    for (int j = 0; j < Q; ++j) {
        int c; cin >> c;
        if (c == 0) {
            //update(i,x)
            int i, x; cin >> i >> x;
            update(i, x);
        }
        else {
            //find(s,t)
            int s, t;
            cin >> s >> t;
            cout << query(s, t + 1, 0, 0, n) << endl;
        }
    }
    return 0;
}

BIT
N個の変数v1,,vN(すべて0で初期化)
2種類のクエリ1,vaに値wを加える2,prefix[1,a]のところの和v1+,,,,+vaを求める
クエリあたりo(logN)時間にしたい
RSQのコード

// Binary Indexed Tree
template<class T>
struct BinaryIndexedTree {
    const int n;
    vector<T> v;
    BinaryIndexedTree(int n) : n(n), v(n, 0) {}
    void add(int i, T x) {
        for (; i < n; i |= i + 1)
            v[i] += x;
    }
    // [0, i)
    T sum(int i) {
        T r = 0;
        for (--i; i >= 0; i = (i & (i + 1)) - 1)
            r += v[i];
        return r;
    }
    // [l, r)
    T sum(int l, int r) {
        return sum(r) - sum(l);
    }
};
int main() {
    int n, q; cin >> n >> q;
    BinaryIndexedTree<int>b(n);
    REP(i, q) {
        int c, x, y;
        cin >> c >> x >> y;
        if (c == 0) {
            b.add(x - 1, y);
        }
        else {
            cout << b.sum(x - 1, y) << endl;
        }
    }
    return 0;
}

bitの例 abc157 E


#include<iostream>
#include<cassert>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
#include<math.h>
#include<queue>
#include<deque>
#include<stack>
#include<cstdio>
#include<utility>
#include<set>
#include<list>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<bitset>
#include<functional>
#include<iterator>
#include<complex>
#include<fstream>
#include<random>
#include<ctype.h>
#include<stdio.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); i++)
#define REP(i, n) FOR(i, 0, n - 1)
#define NREP(i, n) FOR(i, 1, n)
using ll = long long;
using pii = pair<int, int>;
using PII = pair<ll, ll>;
using piii = pair<pii, pii>;
using Pi = pair<int, pii>;
using Graph = vector<vector<int>>;
const int dx[4] = { 0, -1, 1, 0 };
const int dy[4] = { -1, 0, 0, 1 };
bool check(int x, int y) {
    if (0 <= x && x<55 && 0 <= y && y<55)return true;
    else return false;
}
const ll INF = 1e+7;
int gcd(int x, int y) {
    if (x < y)swap(x, y);
    if (y == 0)return x;
    return gcd(y, x%y);
}
void mul(ll a, ll b) {
    a = a * b % INF;
}
using Graph = vector<vector<int>>;

long long modinv(long long a, long long m) {
    long long b = m, u = 1, v = 0;
    while (b) {
        long long t = a / b;
        a -= t * b; swap(a, b);
        u -= t * v; swap(u, v);
    }
    u %= m;
    if (u < 0) u += m;
    return u;
}
const double PI = 3.14159265358979323846;
const int MAX = 510000;
ll fac[MAX], finv[MAX], inv[MAX];
//テーブルをつくる前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;//mod pにおける1,2,,,nの逆元
    for (int i = 2; i < MAX; ++i) {
        fac[i] = fac[i - 1] * i%INF;
        inv[i] = INF - inv[INF%i] * (INF / i) % INF;
        finv[i] = finv[i - 1] * inv[i] % INF;
    }
}

ll COM(int n, int k) {
    if (n < k)return 0;
    if (n < 0 || k < 0)return 0;
    return fac[n] * (finv[k] * finv[n - k] % INF) % INF;
}
double Euclidean_distance(double x1, double y1, double x2, double y2) {
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

int prime[1001000];//i番目の素数
bool is_prime[1001010];//is_prime[i]がtrueならiは素数
                       //n以下の素数の数を返す
int sieve(int n) {
    int p = 0;
    for (int i = 0; i <= n; ++i) {
        is_prime[i] = true;
    }
    is_prime[0] = false;
    is_prime[1] = false;
    for (int i = 2; i <= n; ++i) {
        if (is_prime[i]) {
            prime[p] = i;
            p++;
            for (int j = 2 * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }
    return p;
}

//素因数分解
map<int, int>prime_factor(int n) {
    map<int, int>res;
    for (int i = 2; i*i <= n; ++i) {
        while (n%i == 0) {
            ++res[i];
            n /= i;
        }
    }
    if (n != 1)res[n] = 1;
    return res;
}


ll powmod(ll a, ll k,ll mod) {
    ll ap = a, ans = 1;
    while (k) {
        if (k & 1) {
            ans *= ap;
            ans %= mod;
        }
        ap = ap * ap;
        ap %= mod;
        k >>= 1;
    }
    return ans;
}
ll invi(ll a,ll mod) {
    return powmod(a, mod - 2,mod);
}
//逆元Aを足したときのmodで割った余りは
//+=invi(A)
///////////////////////////////////////

// Binary Indexed Tree
template<class T>
struct BinaryIndexedTree {
    const int n;
    vector<T> v;
    BinaryIndexedTree(int n) : n(n), v(n, 0) {}
    void add(int i, T x) {
        for (; i < n; i |= i + 1)
            v[i] += x;
    }
    // [0, i)
    T sum(int i) {
        T r = 0;
        for (--i; i >= 0; i = (i & (i + 1)) - 1)
            r += v[i];
        return r;
    }
    // [l, r)
    T sum(int l, int r) {
        return sum(r) - sum(l);
    }
};
int main() {
    int n, q;
    string S;
    cin >> n >> S >> q;
    vector<BinaryIndexedTree<int>>bit(26, BinaryIndexedTree<int>(n));
    for (int i = 0; i < n; ++i) {
        bit[S[i] - 'a'].add(i , 1);
    }
    for (int i = 0; i < q; ++i) {
        int t; cin >> t;
        if (t == 1) {
            int k; char c;
            cin >> k >> c;
            bit[S[k - 1] - 'a'].add(k-1, -1);
            bit[c - 'a'].add(k-1, 1);
            S[k - 1] = c;
        }
        else {
            int l, r; cin >> l >> r;
            int ans = 0;
            for (int j = 0; j < 26; ++j) {
                if (bit[j].sum(l-1,r) > 0)ans++;
            }
            cout << ans << endl;
        }
    }
    return 0;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0