時限 :3000ms
題意:
給你n個數,下面有m個詢問,每次詢問區間【l,r】之間不同數的和是多少。
思路:
1.主席樹 500ms。
和spoj DQUERY那道題求區間不同數的個數差不多,區別就是spoj那道題1到n每個點都要更新主席樹那條鏈是+1-1的操作,這個是對那條鏈+num-num的操作。
其實也可以用map存之前數的位置的,但萬一比賽卡你用map呢,還是離散化+lower_bound來存位置吧。
注意主席樹要開40倍的大小。
1e51e5會爆int,要開longlong
/**
* Author : zzy
* Date : 2020-04-06-15.34.56 Monday
*/
#include <bits/stdc++.h>
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (i64 i = 0; i < (i64)(n); ++i)
#define for1(i, n) for (i64 i = 1; i <= (i64)(n); ++i)
#define ford(i, a, b) for (i64 i = (i64)(a); i >= (i64)b; --i)
#define fore(i, a, b) for (i64 i = (i64)(a); i <= (i64)(b); ++i)
#define rep(i, l, r) for (i64 i = (l); i <= (r); i++)
#define per(i, r, l) for (i64 i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((i64)(x).size())
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//注意會爆int,樹的節點值要用long long存
const int maxn = 3*(int)1e4+5;
int tc, a[maxn], b[maxn], t[maxn*40], lt[maxn*40], rt[maxn*40], tot, lst[maxn];
i64 tVal[maxn*40];
int build(int l, int r) {
int root = ++tot;
int mid = (l+r)>>1;
if (l < r) {
lt[root] = build(l, mid);
rt[root] = build(mid+1, r);
}
return root; //這邊一開始沒寫,看了半天,服了
}
int update(int l,int r, int p, int val, int par) {
int root = ++tot;
lt[root] = lt[par]; rt[root] = rt[par]; tVal[root] = tVal[par]+val;
int mid = (l+r)>>1;
if (l < r) {
if (p <= mid) lt[root] = update(l, mid, p, val, lt[par]);
else rt[root] = update(mid+1, r, p, val, rt[par]);
}
return root;
}
i64 query(int l, int r, int p, int idx) {
if (l == r) return tVal[idx];
else {
int mid = (l+r)>>1;
if (p <= mid) {
return query(l, mid, p, lt[idx])+tVal[rt[idx]];
} else {
return query(mid+1, r, p, rt[idx]);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin >> tc;
while (tc--) {
ms(lst, -1);
ms(tVal, 0);
tot = 0;
int n;
cin >> n;
for1(i, n) {
cin >> a[i];
b[i] = a[i];
}
sort(b+1, b+1+n);
int len = unique(b+1, b+1+n)-b-1;
t[0] = build(1, n);
for1(i, n) {
int p = lower_bound(b+1, b+1+len, a[i])-b;
if (lst[p] == -1) {
t[i] = update(1, n, i, a[i], t[i-1]);
} else {
int temp = update(1, n, lst[p], -a[i], t[i-1]);
t[i] = update(1, n, i, a[i], temp);
}
lst[p] = i;
}
int q;
cin >> q;
while (q--) {
int l, r;
cin >> l >> r;
i64 ans = query(1, n, l, t[r]);
cout << ans << '\n';
}
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
2.線段樹離線處理詢問 400ms
現將詢問按照r從小到大排序,然後對每個詢問往右更新,如果之前出現過,就logn更新之前出現的那個位置-1,然後logn更新現在出現的這個位置+1。
/**
* Author : zzy
* Date : 2020-04-07-00.30.30 Monday
*/
#include <bits/stdc++.h>
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 3*(int)1e4+1000;
int tc, n, a[maxn], b[maxn], q, lst[maxn];
i64 tVal[maxn<<2], ans[100100];
struct ss {
int l, r, id;
bool operator < (const ss &oth) const {return r<oth.r;}
}qq[100100]; //這邊一開始開的maxn大,wa了兩發
void pushUp(int node) {
tVal[node] = tVal[node<<1]+tVal[node<<1|1];
}
void update(int node, int l, int r, int p, int val) {
if (l == r) {
tVal[node] += val;
return;
}
int mid = (l+r)>>1;
if (p <= mid) update(node<<1, l, mid, p, val);
else update(node<<1|1, mid+1, r, p, val);
pushUp(node);
}
i64 query(int node, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return tVal[node];
i64 sum = 0;
int mid = (l+r)>>1;
if (ql <= mid) sum += query(node<<1, l, mid, ql, qr);
if (qr > mid) sum += query(node<<1|1, mid+1, r, ql, qr);
return sum;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin >> tc;
while (tc--) {
ms(tVal, 0);
ms(lst, -1);
cin >> n;
for1(i, n) {
cin >> a[i];
b[i] = a[i];
}
sort(b+1, b+1+n);
int len = unique(b+1, b+1+n)-b-1;
cin >> q;
forn(i, q) {
cin >> qq[i].l >> qq[i].r;
qq[i].id = i;
}
sort(qq, qq+q);
int now = 0;
forn(i, q) {
while (now < qq[i].r) {
++now;
int num = lower_bound(b+1, b+1+len, a[now])-b;
if (lst[num] == -1) {
update(1, 1, n, now, a[now]);
} else {
update(1, 1, n, lst[num], -a[now]);
update(1, 1, n, now, a[now]);
}
lst[num] = now;
}
ans[qq[i].id] = query(1, 1, n, qq[i].l, qq[i].r);
}
forn(i, q) cout << ans[i] << '\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
3.樹狀數組 300ms
思路跟線段樹一樣
/**
* Author : zzy
* Date : 2020-04-07-03.12.12 Monday
*/
#include <bits/stdc++.h>
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())
#define lowbit(x) (x&(-x))
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 3*(int)1e4+1000;
const int qmaxn = (int)1e5+1000;
int tc, n, a[maxn], b[maxn], lst[maxn];
i64 ft[maxn], ans[qmaxn];
struct ss {
int l, r, id;
bool operator < (const ss &oth) const {return r<oth.r;}
}qq[qmaxn];
void update(int p, int val) {
for (int i = p; i <= n; i += lowbit(i)) ft[i] += val;
}
i64 query(int p) {
i64 sum = 0;
for (int i = p; i > 0; i -= lowbit(i)) sum += ft[i];
return sum;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin >> tc;
while (tc--) {
ms(ft, 0);
ms(lst, -1);
cin >> n;
for1(i, n) {
cin >> a[i];
b[i] = a[i];
}
sort(b+1, b+1+n);
int len = unique(b+1, b+1+n)-b-1;
int q;
cin >> q;
forn(i, q) {
cin >> qq[i].l >> qq[i].r;
qq[i].id = i;
}
sort(qq, qq+q);
int now = 0;
forn(i, q) {
while (now < qq[i].r) {
++now;
int num = lower_bound(b+1, b+1+len, a[now])-b;
if (lst[num] == -1) {
update(now, a[now]);
} else {
update(lst[num], -a[now]);
update(now, a[now]);
}
lst[num] = now;
}
ans[qq[i].id] = query(qq[i].r)-query(qq[i].l-1);
}
forn(i, q) cout << ans[i] << '\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}