您的位置:首页 > 其它

hdu 3333 Turing Tree(图灵树,线段树,离散化)

2014-08-14 15:59 232 查看
题目大意:

求区间内不同的数字的和。这题用一般性的线段树写的时候没法处理相同的数字。

解题思路:

首先离散化,因为数字太大。

然后读入所有的询问区间,以右端为基准进行排序。这样能保证如果某个数字前面出现过,在原来位置删去,在新位置插入不会影响结果。因为越往后面,区间的右端越大。

然后线段树查询区间和的时候不变。

下面是代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 120009
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL __int64

LL sum[maxn];

void build(int l,int r,int rt)
{
sum[rt]=0;
if(l==r)return ;
int m =(l+r)>>1;
build(lson);
build(rson);
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int l,int r,int rt,int p,int flag,int num)
{
if(l==r)
{
sum[rt]+=flag*num;
return ;
}
int m = (l+r)>>1;
if(m>=p)update(lson,p,flag,num);
else update(rson,p,flag,num);
pushup(rt);
}
LL query(int l,int r,int rt,int L,int R)
{
if(l>=L&&r<=R)return sum[rt];
int m =(l+r)>>1;
LL ans =0;
if(m>=L) ans += query(lson,L,R);
if(m<R) ans += query(rson,L,R);
return ans ;
}
struct node
{
int l,r,id;
} nod[100009];

bool cmp(node a,node b)
{
return a.r<b.r;
}

struct Tem
{
int a,id;
} tem[30009];

bool cmp1(Tem x,Tem y)
{
return x.a<y.a;
}
bool cmp2(Tem x,Tem y)
{
return x.id<y.id;
}
int main()
{
int n,m,i,j,T;
LL an[100009];
int a1[30009];
int vis[30009];
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=0; i<n; i++)
{
scanf("%d",&tem[i].a);
tem[i].id=i+1;
}
sort(tem,tem+n,cmp1);
a1[tem[0].id]=1;

for(i=1; i<n; i++)
{
a1[tem[i].id]=a1[tem[i-1].id];
if(tem[i].a!=tem[i-1].a)a1[tem[i].id]++;
}
sort(tem,tem+n,cmp2);

scanf("%d",&m);
for(i=0; i<m; i++)
{
scanf("%d%d",&nod[i].l,&nod[i].r);
nod[i].id=i;
}
sort(nod,nod+m,cmp);
j=1;
memset(vis,0,sizeof(vis));
build(1,n,1);
for(i=0; i<m; i++)
{
while(j<=nod[i].r)
{
if(vis[a1[j]]!=0)
update(1,n,1,vis[a1[j]],-1,tem[j-1].a);
update(1,n,1,j,1,tem[j-1].a);
vis[a1[j]]=j;
j++;
}
an[nod[i].id] =query(1,n,1,nod[i].l,nod[i].r);
}
for(i=0; i<m; i++)
printf("%I64d\n",an[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu 线段树 离散化