HDU 3333 Turing Tree(線段樹+離線操作)

Mr_Treeeee發表於2020-04-06

Turing Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5385    Accepted Submission(s): 1909


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
 

Author
3xian@GDUT
 

Source
 
題意:
求區間內和,重複的值不算。

POINT:
看了題解,用離線操作,沒想到還有這種操作。
解釋一下就是:
先按照所需求區間的右端點排序。線段樹區間儲存的就是合。
一個一個插入點,如果遇到之前插入過的,把舊的更新成0,新的再插入。這樣就能實現,i這個狀態下 (1-i)區間裡的數字都只出現了一次,然後當有右端點==i時,求一下sum(l-r),儲存答案就行。
然後按照原順序輸出。小細節程式碼裡有註釋。
並不需要離散化。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
#define rt x<<1|1
#define lt x<<1
const int N = 30000*8;
#define  LL long long
LL a[N],sum[N];
map<LL,int> mp;
struct node
{
    int l,r,i;
}q[N];
bool cmd(node c,node b)
{
    return c.r<b.r;
}
void init()
{
    mp.clear();
    memset(q,0,sizeof q);
    memset(sum,0,sizeof sum);
    memset(a,0,sizeof a);
}
void change(int x,int l,int r,int i,LL k)
{
    if(l==r&&r==i) sum[x]=k;
    else
    {
        int mid=(l+r)>>1;
        if(i<=mid) change(lt,l,mid,i,k);
        if(mid<i) change(rt,mid+1,r,i,k);
        sum[x]=sum[lt]+sum[rt];
    }
}
LL query(int x,int l,int r,int ll,int rr)
{
    LL ans=0;
    if(ll<=l&&rr>=r) ans+=sum[x];
    else
    {
        int mid=(l+r)>>1;
        if(ll<=mid) ans+=query(lt,l,mid,ll,rr);
        if(mid<rr) ans+=query(rt,mid+1,r,ll,rr);
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
        }
        int Q;
        scanf("%d",&Q);
        for(int i=1;i<=Q;i++)
        {
            scanf("%d %d",&q[i].l,&q[i].r);
            q[i].i=i;
        }
        sort(q+1,q+1+Q,cmd);
        LL ans[N];
        for(int i=1,j=1;i<=n;i++)
        {
            if(mp[a[i]])
            {
                change(1,1,n,mp[a[i]],0);
                change(1,1,n,i,a[i]);
                mp[a[i]]=i;
            }
            else
            {
                mp[a[i]]=i;
                change(1,1,n,i,a[i]);
            }
            while(j<=Q&&q[j].r==i)//有多個區間的r相等的情況,所以用while
            {
                ans[q[j].i]=query(1,1,n,q[j].l,q[j].r);
                j++;
            }
        }
        for(int i=1;i<=Q;i++)
        {
            printf("%lld\n",ans[i]);
        }


    }
    return 0;
}


相關文章