題目鏈接: /
題目
給定長度爲的序列,各處現過次,第一次出現位置記爲,第二次記爲,求滿足的對數
輸入
第一行是
接下來的兩行則是長度爲的序列。
輸出
輸出滿足的對數
樣例輸入
4
3
2
4
4
1
3
2
1
樣例輸出
3
思路
這道題要用樹狀數組來做。
我們先把某個數第一次出現時叫做這個數的左端點,第二次出現時叫做右端點。
然後按左端點從小到大排序,然後對於每一個點,統計它左右端點之間的標記的個數(就是到過的數的右端點),然後就標記這個數的右端點。
這樣子我們就可以得出答案了。
(至於爲什麼的話,自己推一推吧)
代碼
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int l, r;
}a[100001];
int n, xx, ans, ge[100001];
bool cmp(node x, node y) {
return x.l < y.l;
}
int get(int now) {//得到單點值
int re = 0;
for (int i = now; i > 0; i -= i & -i)
re += ge[i];
return re;
}
void build(int now, int ad) {//單點加值
for (int i = now; i <= 2 * n; i += i & -i)
ge[i] += ad;
}
int main() {
// freopen("circlecross.in", "r", stdin);
// freopen("circlecross.out", "w", stdout);
scanf("%d", &n);//讀入
for (int i = 1; i <= 2 * n; i++) {
scanf("%d", &xx);//讀入
if (!a[xx].l) a[xx].l = i;//第一次出現
else a[xx].r = i;//第二次
}
sort(a + 1, a + n + 1, cmp);//按第一次出現時間從小到大排序
for (int i = 1; i <= n; i++) {
ans += get(a[i].r) - get(a[i].l - 1);//得到以這個數左右端點中的已經到過的數
build(a[i].r, 1);//把數的右端點加入樹狀數組
}
printf("%d", ans);//輸出
// fclose(stdin);
// fclose(stdout);
return 0;
}