HDU_3333 Turing Tree 【线段树 + 离散化】

一、题目

  Turing Tree

二、分析

  这题主要还是在区间的处理上。

  为了保证区间内的数没有重复的,那么可以对区间按右端点从小到大排序,这样对原数组处理时,尽量保证不重复的元素靠右(可以假设右端点固定考虑),就可以保证区间求出来的值是不重复的,对于重复的就把前面位置出现的这个数减掉(即赋值为0)即可。

  由于原数组的数比较大,要记录其之前的位置无法直接开数组,所以需要离散化。后面的就是普通的线段树的单点修改和区间查询了。

三、AC代码

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define Min(a,b) ((a)>(b)?(b):(a))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lson (rt<<1)
#define rson (rt<<1|1)
#define P pair<int, int>
const int MAXN = 3e4;
const int MAXQ = 1e5;
ll A[MAXN + 13], Sum[MAXN<<2];
int Pre[MAXN + 13];
vector<ll> vec;
struct node
{
    int L, R, id;
    bool operator < (const node &t) const {
        return R < t.R;
    }
}B[MAXQ + 13];
ll Ans[MAXQ + 13];

int getPos(ll x)
{
    return lower_bound(vec.begin(), vec.end(), x) - vec.begin(); 
}
void Push_up(int rt)
{
    Sum[rt] = Sum[lson] + Sum[rson];
    return;
}
void Update(int rt, int l, int r, int p, ll val)
{
    if(l == r) {
        Sum[rt] = val;
        return;
    }
    int mid = (l + r) >> 1;
    if(p <= mid)
        Update(lson, l, mid, p, val);
    else 
        Update(rson, mid + 1, r, p, val);
    Push_up(rt);
}
ll Query(int rt, int l, int r, int L, int R)
{
    if(L <= l && r <= R) {
        return Sum[rt];
    }
    int mid = (l + r) >> 1;
    ll ans = 0;
    if(L <= mid)
        ans += Query(lson, l, mid, L, R);
    if(R > mid)
        ans += Query(rson, mid + 1, r, L, R);
    return ans;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    int T;
    scanf("%d", &T);
    while(T--) {
        int N, Q;
        scanf("%d", &N);
        vec.clear();
        for(int i = 1; i <= N; i++) {
            scanf("%lld", &A[i]);
            vec.push_back(A[i]);
        }
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        scanf("%d", &Q);
        for(int i = 0; i < Q; i++) {
            scanf("%d%d", &B[i].L, &B[i].R);
            B[i].id = i;
        }
        sort(B, B + Q);
        memset(Sum, 0, sizeof(Sum));
        memset(Pre, -1, sizeof(Pre));   //某个数字之前出现的位置
        for(int i = 1, j = 0; i <= N; i++) {
            int p = getPos(A[i]);
            if(Pre[p] != -1) {
                Update(1, 1, N, Pre[p], 0);
            }
            Pre[p] = i;
            Update(1, 1, N, i, A[i]);
            for(; j < Q; j++) {
                if(B[j].R != i) {
                    break;
                }
                Ans[B[j].id] = Query(1, 1, N, B[j].L, B[j].R);
            }
        }
        for(int i = 0; i < Q; i++) {
            printf("%lld\n", Ans[i]);
        }
    }
    return 0;
}

 

posted @ 2019-08-30 14:53  Dybala21  阅读(119)  评论(0编辑  收藏  举报