链接:https://ac.nowcoder.com/acm/contest/1084/B
来源:牛客网
Galahad
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
本题推荐BGM:Galahad and Scientific Witchery
魔女要测试骑士的能力,要求他维护一个长度为 的序列,每次要询问一个区间的和。
但是魔女觉得太简单了,骑士能轻松记住 个数作为前缀和。
于是,魔女要求他回答一个区间的和,但如果某一个数在这个区间出现了多次,这个数只能被计算一次。
输出描述:
输出 行,每行一个整数表示这次询问的答案。
示例1
输入
复制
5 3
1 3 3 2 1
1 5
1 3
2 4
输出
复制
6
4
5
/*
和区间不同数字个数板子一样~
*/
解法一:
数状数组:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN = 5e5+5;
int a[MAXN];
LL b[MAXN];
LL ans[MAXN];
int n,m;
struct Node
{
int l,r;
int id;
bool operator<(const Node &a)const
{
return r < a.r;
}
} node[MAXN];
int last[MAXN];
inline int lowbit(int x)
{
return x&-x;
}
void add(int x,int v)
{
for(int i = x; i <= n; i+=lowbit(i))
{
b[i] += v;
}
}
LL sum(int x)
{
LL res = 0;
for(int i = x; i > 0; i-=lowbit(i))
{
res += b[i];
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&node[i].l,&node[i].r);
node[i].id = i;
}
/*
按询问区间中r小的优先排序(r递增排序)
这样维护的时候就可以只保留最后一个不重复的数字
*/
sort(node+1,node+m+1);
for(int i = 1; i <= m; i++)
{
for(int j = node[i-1].r+1; j <= node[i].r; j++)
{
if(last[a[j]])//前面出现过,那个位置置为0
add(last[a[j]],-a[j]);
add(j,a[j]);//当前位置加当前位置对应的值
last[a[j]] = j;//记录位置
}
ans[node[i].id] = sum(node[i].r)-sum(node[i].l-1);
}
for(int i = 1; i <= m; i++)
{
printf("%lld\n",ans[i]);
}
return 0;
}
解法二:
线段树:
#include <bits/stdc++.h>
#define lson rt<<1,l, mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int N = 5e5+5;
typedef long long LL;
LL sum[N<<2];
int a[N];
int last[N];
LL ans[N];
struct Node
{
int l,r;
int id;
bool operator<(const Node &a)const
{
return r < a.r;
}
} node[N];
inline void push_up(int rt)
{
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
/*
void build(int rt,int l,int r)
{
if(l == r) //叶子节点
{
sum[l] = a[l];
return;
}
int mid = (l+r)>>1;
//建左子树
build(lson);
//建右子树
build(rson);
//向上更新信息
push_up(rt);
}
*/
//单点更新
void update_point(int pos,int v,int rt,int l,int r)
{
if(l == r)
{
sum[rt] = v;
return;
}
int mid = (l+r) >> 1;
if(pos <= mid) //在左子树
update_point(pos,v,lson);
else
update_point(pos,v,rson);
//向上更新信息
push_up(rt);
}
//区间查询,查询【L,R】
LL query(int L,int R,int rt,int l,int r)
{
if(L <= l && r <= R) //是查询区间子集
{
return sum[rt];
}
int mid = (l + r) >> 1;
LL res = 0;
if(L <= mid) res += query(L,R,lson);
if(R > mid) res += query(L,R,rson);
return res;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&node[i].l,&node[i].r);
node[i].id = i;
}
sort(node+1,node+m+1);
//build(1,1,n);
for(int i = 1; i <= m; i++)
{
for(int j = node[i-1].r+1; j <= node[i].r; j++)
{
if(last[a[j]])
update_point(last[a[j]],0,1,1,n);
last[a[j]] = j;
update_point(j,a[j],1,1,n);
}
ans[node[i].id] = query(node[i].l,node[i].r,1,1,n);
}
for(int i = 1; i <= m; i++)
{
printf("%lld\n",ans[i]);
}
return 0;
}