2016 UESTC Training for Data Structures K - 郭大侠与甲铁城 树状数组+离线操作

K - 郭大侠与甲铁城

Time Limit: 1500/800MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit  Status


现在在这个城市中有n个卡巴内,每个卡巴内都有他自身的属性a[i],郭大侠的贯筒能够一次性击穿[L,R]区间中拥有不同属性的怪物!

为了足够强的发挥自己的武器的实力,郭大侠必须提前知道自己的一次性贯筒能够击杀多少只怪物。

现在开始计算吧!

Input

第一行给你n,q,表示有n个卡巴内,q次询问

第二行有n个整数,表示每一个卡巴内的属性a[i]

接下来q行,每行两个整数Li,Ri,表示询问。

1<=n,q<=100000

1<=Li<=Ri<=n

1<=a[i]<=10000

Output

对于每一个询问,输出答案!

Sample input and output

Sample Input Sample Output
5 3
1 2 3 1 1
1 3
1 4
3 5
3
3
2

Source

2016 UESTC Training for Data Structures  Problem K

My Solution

树状数组+离线操作

先把查询去区间储存下来然后按做端点排序
每次查询一个区间,
      必须按照前面留下的lastRight到到这个区间的右端点扫一遍,
      如果当中有一个value上次出现的位置不在这里,
      则把前面的value从树状数组中去掉,
      去掉的时候用add(last[value], -1),
      并更新last[value]。
      把答案放在ans[maxn]里全部处理完在按照查询出现的顺序输出
ans[i] = get(R) - get(L - 1);
复杂度 O(q*logn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 8;
int n;
int value[maxn], last[maxn], ans[maxn];
int Tree[maxn];

struct Query{
    int l, r;
    int Index;
} querys[maxn];

bool cmp(const Query& a, const Query& b)
{
    return a.r < b.r;
}

inline int lowbit(int x)
{
    return (x&-x);
}

void add(int x, int value)
{
    for(int i = x; i <= n; i += lowbit(i))
        Tree[i] += value;
}

int get(int x)
{
    int sum = 0;
    for(int i = x; i; i -= lowbit(i))
        sum += Tree[i];
    return sum;
}
//初始化以后用的时候运算速度快一些
inline void init()
{
     memset(value, 0, sizeof value);
     memset(Tree, 0, sizeof Tree);
     memset(last, 0, sizeof last);     //这个必须置零
     memset(ans, 0, sizeof ans);
     memset(querys, 0, sizeof querys); //这个也能置零的吧
}

int main()
{
    #ifdef LOCAL
    freopen("a.txt", "r", stdin);
    #endif // LOCAL
    int q;
    scanf("%d%d", &n, &q);
    init();
    for(int i = 1; i <= n; i++){
        scanf("%d", &value[i]);
        add(i, 1);
        if(!last[value[i]]) last[value[i]] = i;
    }
    for(int i = 1; i <= q; i++){
        scanf("%d%d", &querys[i].l, &querys[i].r);
        querys[i].Index = i;
    }
    sort(querys + 1, querys + q + 1, cmp);
    int lastRight = 1;
    for(int i = 1; i <= q; i++){
        for(int j = lastRight; j <= querys[i].r; j++){
            if(last[value[j]] != j){
                add(last[value[j]], -1);
                last[value[j]] = j;
            }
        }
        lastRight = querys[i].r;
        ans[querys[i].Index] = get(querys[i].r) - get(querys[i].l - 1); //!这里注意减个1
    }
    for(int i = 1; i <= q; i++)
        printf("%d\n", ans[i]);
    return 0;
}

Thank you !
                                                                                                                                               ------from  ProLights






你可能感兴趣的:(ACM,for,Data,Training,uestc,2016,structures,树状数组+离线查询)