hdu 3333 (主席樹在線求區間不同數的個數 or 線段樹或者樹狀數組離線詢問處理 )

題目鏈接

時限 :3000ms

題意:
給你n個數,下面有m個詢問,每次詢問區間【l,r】之間不同數的和是多少。

思路:
1.主席樹 500ms。
和spoj DQUERY那道題求區間不同數的個數差不多,區別就是spoj那道題1到n每個點都要更新主席樹那條鏈是+1-1的操作,這個是對那條鏈+num-num的操作。

其實也可以用map存之前數的位置的,但萬一比賽卡你用map呢,還是離散化+lower_bound來存位置吧。

注意主席樹要開40倍的大小。
1e5
1e5會爆int,要開longlong

/**
* Author : zzy
* Date : 2020-04-06-15.34.56 Monday
*/
#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (i64 i = 0; i < (i64)(n); ++i)
#define for1(i, n) for (i64 i = 1; i <= (i64)(n); ++i)
#define ford(i, a, b) for (i64 i = (i64)(a); i >= (i64)b; --i)
#define fore(i, a, b) for (i64 i = (i64)(a); i <= (i64)(b); ++i)
#define rep(i, l, r) for (i64 i = (l); i <= (r); i++)
#define per(i, r, l) for (i64 i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((i64)(x).size())

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

//注意會爆int,樹的節點值要用long long存
const int maxn = 3*(int)1e4+5;
int tc, a[maxn], b[maxn], t[maxn*40], lt[maxn*40], rt[maxn*40], tot, lst[maxn];
i64 tVal[maxn*40];

int build(int l, int r) {
    int root = ++tot;
    int mid = (l+r)>>1;
    if (l < r) {
        lt[root] = build(l, mid);
        rt[root] = build(mid+1, r);
    }
    return root; //這邊一開始沒寫,看了半天,服了
}
int update(int l,int r, int p, int val, int par) {
    int root = ++tot;
    lt[root] = lt[par]; rt[root] = rt[par]; tVal[root] = tVal[par]+val;
    int mid = (l+r)>>1;
    if (l < r) {
        if (p <= mid) lt[root] = update(l, mid, p, val, lt[par]);
        else rt[root] = update(mid+1, r, p, val, rt[par]);
    }
    return root;
}
i64 query(int l, int r, int p, int idx) {
    if (l == r) return tVal[idx];
    else {
        int mid = (l+r)>>1;
        if (p <= mid) {
            return query(l, mid, p, lt[idx])+tVal[rt[idx]];
        } else {
            return query(mid+1, r, p, rt[idx]);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    cin >> tc;
    while (tc--) {
        ms(lst, -1);
        ms(tVal, 0);
        tot = 0;
        int n;
        cin >> n;
        for1(i, n) {
            cin >> a[i];
            b[i] = a[i];
        }
        sort(b+1, b+1+n);
        int len = unique(b+1, b+1+n)-b-1;
        t[0] = build(1, n);
        for1(i, n) {
            int p = lower_bound(b+1, b+1+len, a[i])-b;
            if (lst[p] == -1) {
                t[i] = update(1, n, i, a[i], t[i-1]);
            } else {
                int temp = update(1, n, lst[p], -a[i], t[i-1]);
                t[i] = update(1, n, i, a[i], temp);
            }
            lst[p] = i;
        }
        int q;
        cin >> q;
        while (q--) {
            int l, r;
            cin >> l >> r;
            i64 ans = query(1, n, l, t[r]);
            cout << ans << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

2.線段樹離線處理詢問 400ms
現將詢問按照r從小到大排序,然後對每個詢問往右更新,如果之前出現過,就logn更新之前出現的那個位置-1,然後logn更新現在出現的這個位置+1。

/**
* Author : zzy
* Date : 2020-04-07-00.30.30 Monday
*/
#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 3*(int)1e4+1000;
int tc, n, a[maxn], b[maxn], q, lst[maxn];
i64 tVal[maxn<<2], ans[100100];
struct ss {
    int l, r, id;
    bool operator < (const ss &oth) const {return r<oth.r;}
}qq[100100]; //這邊一開始開的maxn大,wa了兩發

void pushUp(int node) {
    tVal[node] = tVal[node<<1]+tVal[node<<1|1];
}
void update(int node, int l, int r, int p, int val) {
    if (l == r) {
        tVal[node] += val;
        return;
    }
    int mid = (l+r)>>1;
    if (p <= mid) update(node<<1, l, mid, p, val);
    else update(node<<1|1, mid+1, r, p, val);
    pushUp(node);
}
i64 query(int node, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr) return tVal[node];
    i64 sum = 0;
    int mid = (l+r)>>1;
    if (ql <= mid) sum += query(node<<1, l, mid, ql, qr);
    if (qr > mid) sum += query(node<<1|1, mid+1, r, ql, qr);
    return sum;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    cin >> tc;
    while (tc--) {
        ms(tVal, 0);
        ms(lst, -1);
        cin >> n;
        for1(i, n) {
            cin >> a[i];
            b[i] = a[i];
        }
        sort(b+1, b+1+n);
        int len = unique(b+1, b+1+n)-b-1;
        cin >> q;
        forn(i, q) {
            cin >> qq[i].l >> qq[i].r;
            qq[i].id = i;
        }
        sort(qq, qq+q);
        int now = 0;
        forn(i, q) {
            while (now < qq[i].r) {
                ++now;
                int num = lower_bound(b+1, b+1+len, a[now])-b;
                if (lst[num] == -1) {
                    update(1, 1, n, now, a[now]);
                } else {
                    update(1, 1, n, lst[num], -a[now]);
                    update(1, 1, n, now, a[now]);
                }
                lst[num] = now;
            }
            ans[qq[i].id] = query(1, 1, n, qq[i].l, qq[i].r);
        }
        forn(i, q) cout << ans[i] << '\n';
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

3.樹狀數組 300ms
思路跟線段樹一樣

/**
* Author : zzy
* Date : 2020-04-07-03.12.12 Monday
*/
#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())
#define lowbit(x) (x&(-x))

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 3*(int)1e4+1000;
const int qmaxn = (int)1e5+1000;
int tc, n, a[maxn], b[maxn], lst[maxn];
i64 ft[maxn], ans[qmaxn];
struct ss {
    int l, r, id;
    bool operator < (const ss &oth) const {return r<oth.r;}
}qq[qmaxn];

void update(int p, int val) {
    for (int i = p; i <= n; i += lowbit(i)) ft[i] += val;
}
i64 query(int p) {
    i64 sum = 0;
    for (int i = p; i > 0; i -= lowbit(i)) sum += ft[i];
    return sum;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    cin >> tc;
    while (tc--) {
        ms(ft, 0);
        ms(lst, -1);
        cin >> n;
        for1(i, n) {
            cin >> a[i];
            b[i] = a[i];
        }
        sort(b+1, b+1+n);
        int len = unique(b+1, b+1+n)-b-1;
        int q;
        cin >> q;
        forn(i, q) {
            cin >> qq[i].l >> qq[i].r;
            qq[i].id = i;
        }
        sort(qq, qq+q);
        int now = 0;
        forn(i, q) {
            while (now < qq[i].r) {
                ++now;
                int num = lower_bound(b+1, b+1+len, a[now])-b;
                if (lst[num] == -1) {
                    update(now, a[now]);
                } else {
                    update(lst[num], -a[now]);
                    update(now, a[now]);
                }
                lst[num] = now;
            }
            ans[qq[i].id] = query(qq[i].r)-query(qq[i].l-1);
        }
        forn(i, q) cout << ans[i] << '\n';
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章