HDU 3333 Turing Tree

离线操作,区间求和(线段树或树状数组)。

将询问按照$q[i].R$从小到大进行排序,然后逐个更新$a[i]$,如果之前$a[i]$不存在,那么直接更新进去,如果之前$a[i]$存在,那么把之前位置的$a[i]$删掉,更新成现在位置。这样操作就能保证:$i$位置更新完毕之后,存在的数都是不同的,并且都是最靠近$i$的。

如果某个$a[i]$更新完之后,发现有$q[i].R==i$,那么这些询问已经可以得出答案了。最后按照输入的顺序输出即可。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}

const int maxn=30010;
int T,n;
LL a[maxn],c[maxn];
struct X { int id,L,R;LL ans; }q[100010];

bool cmp(X a,X b) { return a.R<b.R; }
bool cmp1(X a,X b) { return a.id<b.id; }

int lowbit(int x) { return x&(-x); }
void update(int p,LL v)
{
    while(p<=n) c[p]=c[p]+v,p=p+lowbit(p);
}
LL sum(int p)
{
    LL res=0;
    while(p>0) res=res+c[p],p=p-lowbit(p);
    return res;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        map<LL,int>m;
        int Q; scanf("%d",&Q);
        for(int i=1;i<=Q;i++) scanf("%d%d",&q[i].L,&q[i].R),q[i].id=i;
        sort(q+1,q+1+Q,cmp); int p=1; memset(c,0,sizeof c);
        for(int i=1;i<=n;i++)
        {
            int h=m[a[i]];
            if(h!=0) update(h,-a[i]); update(i,a[i]); m[a[i]]=i;
            while(p<=Q&&q[p].R==i) q[p].ans=sum(q[p].R)-sum(q[p].L-1), p++;
        }
        sort(q+1,q+1+Q,cmp1);
        for(int i=1;i<=Q;i++) printf("%lld\n",q[i].ans);
    }
    return 0;
}

 

posted @ 2016-08-25 08:06  Fighting_Heart  阅读(238)  评论(0编辑  收藏  举报