传送门:HDU 3333
题意
给定一个长为n的序列, 做m次查询, 查询结果为区间内只出现一次的数字集合之和
题解
刚开始想的读入时用map映射,如果前面出现过, 线段树之前出现位置结点为0当前点原值, 没出现的话直接原值, 但是发现这样只能查询右端为当前位置左端为1的结点, 所以要先对查询做处理
查询预处理是对查询做r递增排序, 同时要有个idx对应查询下标
所以为了实现全部查询, 应该用离线处理, 即读入所有查询, 处理后处理
了解这个, 就可以求解了
查询
对右端排序后, 没插入一个线段树结点(更新树状数组)的时候, 处理查询右端是i的查询
AC code:
/*adrui's submission
*Language : C++
*Result : Accepted
*File Name: HDU 3333
*Favorite : Dragon Balls
*love : yy
*Standing in the Hall of Fame
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
typedef long long LL;
#define debug 0
#define M(a, b) memset(a, b, sizeof(a))
#define lowbit(x) (x & (-x))
const int maxn = 30000 + 5;
int n, m;
int a[maxn];
LL c[maxn], ans[100010];
struct node {
int l, r, idx;
bool operator < (const node& rhs) {
return r < rhs.r;//r升序
}
}q[100010];
void add(int x, int v)
{
while (x <= n) {
c[x] += v;
x += lowbit(x);
}
}
LL getSum(int x) {
LL res = 0;
while (x) {
res += c[x];
x -= lowbit(x);
}
return res;
}
int main() {
#if debug
freopen("in.txt", "r", stdin);
#endif //debug
cin.tie(0);
cin.sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
map<int, int>mp;//map映射
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
cin >> m;
for (int i = 1; i <= m; ++i) {
cin >> q[i].l >> q[i].r;
q[i].idx = i;//对应查询下标
}
sort(q + 1, q + m + 1);//离散化
M(c, 0);
int cnt = 1;
for (int i = 1; i <= n; ++i) {
if (!mp[a[i]]) {//没出现过直接更新
add(i, a[i]);
mp[a[i]] = i;
}
else {
add(mp[a[i]], -a[i]);//出现过
add(i, a[i]);
mp[a[i]] = i;
}
while (q[cnt].r == i && cnt <= m) {//处理右端为i的查询
ans[q[cnt].idx] = getSum(q[cnt].r) - getSum(q[cnt].l - 1);//sum
++cnt;
}//while退出后, q[cnt].r >= i + 1
}
for (int i = 1; i <= m; ++i)
cout << ans[i] << endl;
}
return 0;
}
zkw线段树
/*adrui's submission
*Language : C++
*Result : Accepted
*File Name: HDU 3333
*Favorite : Dragon Balls
*love : yy
*Standing in the Hall of Fame
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
typedef long long LL;
#define debug 1
#define M(a, b) memset(a, b, sizeof(a))
#define lowbit(x) (x & (-x))
const int maxn = 30000 + 5;
int n, m, M;
int a[maxn];
LL c[maxn << 2], ans[100010];
struct node {
int l, r, idx;
bool operator < (const node& rhs) {
return r < rhs.r;
}
}q[100010];
void build() {
for (M = 1; M <= n + 1; M <<= 1);
for (int i = 1; i <= n; ++i) {
cin >> c[i + M];
}
for (int i = M - 1; i >= 1; --i) {
c[i] = c[i << 1] + c[i << 1 | 1];
}
}
void add(int x, int v)
{
for (c[x += M] = v, x >>= 1; x; x >>= 1) {
c[x] = c[x << 1] + c[x << 1 | 1];
}
}
LL getSum(int l, int r) {
LL res = 0;
l += M - 1;
r += M + 1;
while (r ^ l ^ 1) {
if (~l & 1) res += c[l + 1];
if (r & 1) res += c[r - 1];
l >>= 1;
r >>= 1;
}
return res;
}
int main() {
#if debug
freopen("in.txt", "r", stdin);
#endif //debug
cin.tie(0);
cin.sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
M(c, 0);
map<int, int>mp;
cin >> n;
build();//建树
cin >> m;
for (int i = 1; i <= m; ++i) {
cin >> q[i].l >> q[i].r;
q[i].idx = i;
}
sort(q + 1, q + m + 1);
int cnt = 1;
for (int i = 1; i <= n; ++i) {
if (!mp[c[i + M]]) {
mp[c[i + M]] = i;
}
else {
add(mp[c[i + M]], 0);//略搓.. 第二出现上一个结点赋0
mp[c[i + M]] = i;
}
while (q[cnt].r == i && cnt <= m) {
ans[q[cnt].idx] = getSum(q[cnt].l, q[cnt].r);
++cnt;
}
}
for (int i = 1; i <= m; ++i)
cout << ans[i] << endl;
}
return 0;
}