• Turing Tree_线段树&树状数组


    Problem Description
    After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because Turing Tree could easily have the solution. As well, wily 3xian made lots of new problems about intervals. So, today, this sick thing happens again...

    Now given a sequence of N numbers A1, A2, ..., AN and a number of Queries(i, j) (1≤i≤j≤N). For each Query(i, j), you are to caculate the sum of distinct values in the subsequence Ai, Ai+1, ..., Aj.
     
    Input
    The first line is an integer T (1 ≤ T ≤ 10), indecating the number of testcases below.
    For each case, the input format will be like this:
    * Line 1: N (1 ≤ N ≤ 30,000).
    * Line 2: N integers A1, A2, ..., AN (0 ≤ Ai ≤ 1,000,000,000).
    * Line 3: Q (1 ≤ Q ≤ 100,000), the number of Queries.
    * Next Q lines: each line contains 2 integers i, j representing a Query (1 ≤ i ≤ j ≤ N).
     
    Output
    For each Query, print the sum of distinct values of the specified subsequence in one line.
     
    Sample Input
    2 3 1 1 4 2 1 2 2 3 5 1 1 2 1 3 3 1 5 2 4 3 5
     
    Sample Output
    1 5 6 3 6

    【题意】给出n个数,然后提出m个问题,求区间内不重复的数之和。

    【思路】先按查询的右坐标升序排列(保证我查询的改动不会影响到后面查询的结果)。把每个数放进线段树的时候,先判断再之前他有没有在线段树,如果在,则删除它,并把他的位置更新到当前点。

     线段树:

    #include<iostream>
    #include<stdio.h>
    #include<map>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    typedef long long int LL;
    const int N=300000+10;
    const int M=100000+10;
    int n,m;
    struct node1
    {
        int l,r;
        LL num;
    
    }sum[N*4];
    struct node
    {
        int ll,rr,index;
    
    }q[M];
    bool cmp(node x,node y)//按他的右边界排序
    {
        return x.rr<y.rr;
    }
    LL a[N];
    map<LL,int>mp;//记录是否出现过相同的数,如果有记录位置
    LL ans[M];
    void build(int k,int l,int r)//建树
    {
        sum[k].l=l;
        sum[k].r=r;
        sum[k].num=0;
        if(l==r) return ;
        int mid=l+r>>1;
        build(k*2,l,mid);
        build(k*2+1,mid+1,r);
    }
    void update(int k,int l,int r,int x,LL v)//更新结点的值
    {
        if(l==r)
        {
            sum[k].num+=v;
            return ;
        }
        int mid=l+r>>1;
        if(x<=mid) update(k*2,l,mid,x,v);
        else update(k*2+1,mid+1,r,x,v);
        sum[k].num=sum[k*2].num+sum[k*2+1].num;
    }
    LL query(int k,int l,int r,int ll,int rr)//查询区间的值
    {
       if(l>=ll&&r<=rr)
        {
            return sum[k].num;
        }
        int mid=l+r>>1;
        LL res=0;
        if(ll<=mid) res+=query(k*2,l,mid,ll,rr);
        if(rr>mid) res+=query(k*2+1,mid+1,r,ll,rr);
        return res;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            mp.clear();
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%I64d",&a[i]);
            }
            build(1,1,n);
            scanf("%d",&m);
            for(int i=0;i<m;i++)
            {
                 scanf("%d%d",&q[i].ll,&q[i].rr);
                 q[i].index=i;
            }
            sort(q,q+m,cmp);
            int k=1;
            for(int i=0;i<m;i++)
            {
                for(;k<=q[i].rr;k++)
                {
                    if(mp[a[k]]!=0) update(1,1,n,mp[a[k]],-a[k]);//如果曾经出现过,则将以前的结点删去
                    mp[a[k]]=k;//将位置赋给当前的结点
                    update(1,1,n,k,a[k]);//将当前结点更新到树中
                }
                ans[q[i].index]=query(1,1,n,q[i].ll,q[i].rr);
            }
            for(int i=0;i<m;i++) printf("%I64d
    ",ans[i]);
        }
        return 0;
    }

    树状数组:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<map>
    #include<algorithm>
    using namespace std;
    const int N=30000+10;
    int n,m,a[N];
    long long sum[N*4],ans[N*4];
    map<int,int >mp;
    struct node
    {
        int l,r,id;
        bool operator<(const node &a)const{
            if(r==a.r) return l<a.l;
            return r<a.r;
        }
    }q[N*4];
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int p,int v)
    {
        while(p<=n)
        {
            sum[p]+=v;
            p+=lowbit(p);
        }
    }
    long long int  query(int p)
    {
        long long int res=0;
        while(p)
        {
            res+=sum[p];
            p-=lowbit(p);
        }
        return res;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            mp.clear();
            memset(sum,0,sizeof(sum));
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            scanf("%d",&m);
            for(int i=0;i<m;i++)
            {
                int l,r;
                scanf("%d%d",&l,&r);
                q[i].l=l;q[i].r=r;q[i].id=i;
            }
            sort(q,q+m);
            int cnt=0;
            for(int i=1;i<=n;i++)
            {
                if(mp.find(a[i])==mp.end())//在mp中没有找到
                {
                    update(i,a[i]);
                    mp[a[i]]=i;
                }
                else
                {
                    update(i,a[i]);
                    update(mp[a[i]],-a[i]);
                    mp[a[i]]=i;
                }
                while(q[cnt].r==i)
                {
                    ans[q[cnt].id]=query(q[cnt].r)-query(q[cnt].l-1);
                    cnt++;
                }
            }
            for(int i=0;i<m;i++) printf("%lld
    ",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    vue之路由的命名视图实现经典布局
    vue之路由的嵌套 子路由
    AngularJS阻止事件冒泡$event.stopPropagation()
    Vue之路由规则中定义参数 传参方式2 params
    前台页面中的Cookie存取删除,以及Cookie的跨域问题
    关于Cookie中的Expire问题和删除Cookie那点事儿
    4-索引中的那些操作
    3-在字符串内插中的神奇用法
    2-for循环之特别的写法与神奇的Override
    1-在C#中的数字 int double
  • 原文地址:https://www.cnblogs.com/iwantstrong/p/6042969.html
Copyright © 2020-2023  润新知