zoukankan      html  css  js  c++  java
  • Hdu-3333 Turning Tree (离线树状数组/线段树)

    Hdu-3333 Turning Tree

    题目大意:先给出n个数字。面对q个询问区间,输出这个区间不同数的和。

    题解:这道题有多重解法。我另一篇博客写了分块的解法  HDU-3333 Turing Tree 分块求区间不同数和 。

    这里讲一下离线树状数组或者线段树的解法。

    先讲一下我们在线(按询问顺序)做这道题会有什么麻烦。因为一个区间重复的数我们只算一个,那么我们认为对于一个区间,重复的数我们只算最接近区间右段点的哪一个。但是因为按询问顺序,它的右端点是会起伏的。所以我们不好统计到底对于每一个询问区间,哪一个才是该区间重复数中有效的哪一个。

    那么我们转变一下思路。改成离线算法。先把询问区间按右端点排序。那么因为区间右段点的单调性,按照这个顺序我们可以只算重复数的最右边的那个。

    具体做法是排序询问右端点r,把1-r的数都加入到树状数组。如果该数在前面有重复数last[i]。那么就把last[i]的值在树状数组去掉,把r点的值在树状数组上加上。那么保证在1-r内每个数只会出现一次。

    AC代码如下:

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<algorithm>
    using namespace std;
    const int N=30000+10;
    const int M=100000+10;
    struct node{
        int x,y,num;
        bool operator < (const node& t) {
            return y<t.y;
        }
    }q[M];
    int n,m,a[N];
    long long sum[2*N],ans[M],last[N];
    map<int,int> lst;
    
    int lowbit(int x) { return x&(-x); }
    
    void update(int x,int v) {
        while (x<=n) {
            sum[x]+=v;
            x+=lowbit(x);
        }
    }
    
    long long query(int x) {
        long long ans=0;
        while (x) {
            ans+=sum[x];
            x-=lowbit(x);
        }
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--) {
            scanf("%d",&n);
            for (int i=1;i<=n;i++) scanf("%d",&a[i]);
            lst.clear();
            for (int i=1;i<=n;i++) last[i]=0;
            for (int i=1;i<=n;i++) {
                last[i]=lst[a[i]];
                lst[a[i]]=i;
            }
            
            scanf("%d",&m);
            for (int i=1;i<=m;i++) {
                scanf("%d%d",&q[i].x,&q[i].y);
                q[i].num=i;
            }
            
            sort(q+1,q+m+1);
            int now=0;
            for (int i=0;i<=n;i++) sum[i]=0;
            for (int i=1;i<=m;i++) {
                while (now<q[i].y) {
                    now++;
                    update(now,a[now]);
                    if (last[now]) update(last[now],-a[now]);
                }
                ans[q[i].num]=query(q[i].y)-query(q[i].x-1);
            }
            for (int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    poj 图算法
    类里二级排序函数使用
    数学题目(高斯消元)
    多校联合比赛部分题目
    poj 3007 & poj 3096
    优先队列
    hdu 各种 A + B
    几道数学题目
    今天下午
    Java常用的几种设计模式
  • 原文地址:https://www.cnblogs.com/clno1/p/9642989.html
Copyright © 2011-2022 走看看