HDU 3333 树状数组(线段树) + 离散化 + 离线处理

传送门:HDU 3333

题意

 给定一个长为n的序列, 做m次查询, 查询结果为区间内只出现一次的数字集合之和


题解

刚开始想的读入时用map映射,如果前面出现过, 线段树之前出现位置结点为0当前点原值, 没出现的话直接原值, 但是发现这样只能查询右端为当前位置左端为1的结点, 所以要先对查询做处理
查询预处理是对查询做r递增排序, 同时要有个idx对应查询下标
所以为了实现全部查询, 应该用离线处理, 即读入所有查询, 处理后处理
了解这个, 就可以求解了


查询

对右端排序后, 没插入一个线段树结点(更新树状数组)的时候, 处理查询右端是i的查询


AC code:

/*adrui's submission
 *Language : C++
 *Result : Accepted
 *File Name: HDU 3333
 *Favorite : Dragon Balls
 *love : yy
 *Standing in the Hall of Fame
 */

#include
#include
#include
#include
using namespace std;

typedef long long LL;

#define debug 0
#define M(a, b) memset(a, b, sizeof(a))
#define lowbit(x) (x & (-x))

const int maxn = 30000 + 5;

int n, m;
int a[maxn];
LL c[maxn], ans[100010];

struct node {
    int l, r, idx;

    bool operator < (const node& rhs) {
        return r < rhs.r;//r升序
    }
}q[100010];

void add(int x, int v) 
{
    while (x <= n) {
        c[x] += v;
        x += lowbit(x);
    }
}

LL getSum(int x) {

    LL res = 0;

    while (x) {
        res += c[x];
        x -= lowbit(x);
    }

    return res;
}

int main() {
#if debug
    freopen("in.txt", "r", stdin);
#endif //debug

    cin.tie(0);
    cin.sync_with_stdio(false);

    int t;
    cin >> t;

    while (t--) {
        map<int, int>mp;//map映射
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }

        cin >> m;
        for (int i = 1; i <= m; ++i) {
            cin >> q[i].l >> q[i].r;
            q[i].idx = i;//对应查询下标
        }

        sort(q + 1, q + m + 1);//离散化

        M(c, 0);
        int cnt = 1;
        for (int i = 1; i <= n; ++i) {
            if (!mp[a[i]]) {//没出现过直接更新
                add(i, a[i]);
                mp[a[i]] = i;
            }
            else {
                add(mp[a[i]], -a[i]);//出现过
                add(i, a[i]);
                mp[a[i]] = i;
            }

            while (q[cnt].r == i && cnt <= m) {//处理右端为i的查询
                ans[q[cnt].idx] = getSum(q[cnt].r) - getSum(q[cnt].l - 1);//sum
                ++cnt;
            }//while退出后, q[cnt].r >= i + 1
        }

        for (int i = 1; i <= m; ++i)
            cout << ans[i] << endl;
    }
    return 0;
}

zkw线段树

/*adrui's submission
 *Language : C++
 *Result : Accepted
 *File Name: HDU 3333
 *Favorite : Dragon Balls
 *love : yy
 *Standing in the Hall of Fame
 */

#include
#include
#include
#include
using namespace std;

typedef long long LL;

#define debug 1
#define M(a, b) memset(a, b, sizeof(a))
#define lowbit(x) (x & (-x))

const int maxn = 30000 + 5;

int n, m, M;
int a[maxn];
LL c[maxn << 2], ans[100010];

struct node {
    int l, r, idx;

    bool operator < (const node& rhs) {
        return r < rhs.r;
    }
}q[100010];

void build() {
    for (M = 1; M <= n + 1; M <<= 1);
    for (int i = 1; i <= n; ++i) {
        cin >> c[i + M];
    }

    for (int i = M - 1; i >= 1; --i) {
        c[i] = c[i << 1] + c[i << 1 | 1];
    }
}
void add(int x, int v) 
{
    for (c[x += M] = v, x >>= 1; x; x >>= 1) {
        c[x] = c[x << 1] + c[x << 1 | 1];
    }
}

LL getSum(int l, int r) {

    LL res = 0;

    l += M - 1;
    r += M + 1;
    while (r ^ l ^ 1) {
        if (~l & 1) res += c[l + 1];
        if (r & 1) res += c[r - 1];
        l >>= 1;
        r >>= 1;
    }

    return res;
}

int main() {
#if debug
    freopen("in.txt", "r", stdin);
#endif //debug

    cin.tie(0);
    cin.sync_with_stdio(false);

    int t;
    cin >> t;

    while (t--) {
        M(c, 0);
        map<int, int>mp;
        cin >> n;
        build();//建树

        cin >> m;
        for (int i = 1; i <= m; ++i) {
            cin >> q[i].l >> q[i].r;
            q[i].idx = i;
        }

        sort(q + 1, q + m + 1);


        int cnt = 1;
        for (int i = 1; i <= n; ++i) {
            if (!mp[c[i + M]]) {
                mp[c[i + M]] = i;
            }
            else {
                add(mp[c[i + M]], 0);//略搓.. 第二出现上一个结点赋0
                mp[c[i + M]] = i;
            }

            while (q[cnt].r == i && cnt <= m) {
                ans[q[cnt].idx] = getSum(q[cnt].l, q[cnt].r);
                ++cnt;
            }
        }

        for (int i = 1; i <= m; ++i)
            cout << ans[i] << endl;
    }
    return 0;
}

你可能感兴趣的:(tree),HDU,数据结构-树状数组)