As most of the ACMers, wy's next target is algorithms, too. wy is clever, so he can learn most of the algorithms quickly. After a short time, he has learned a lot. One day, mostleg asked him that how many he had learned. That was really a hard problem, so wy wanted to change to count other things to distract mostleg's attention. The following problem will tell you what wy counted.
Given 2N integers in a line, in which each integer in the range from 1 to N will appear exactly twice. You job is to choose one integer each time and erase the two of its appearances and get a mark calculated by the differece of there position. For example, if the first 3 is in position 86 and the second 3 is in position 88, you can get 2 marks if you choose to erase 3 at this time. You should notice that after one turn of erasing, integers' positions may change, that is, vacant positions (without integer) in front of non-vacant positions is not allowed.
Input
There are multiply test cases. Each test case contains two lines.
The first line: one integer N(1 <= N <= 100000).
The second line: 2N integers. You can assume that each integer in [1,N] will appear just twice.
Output
One line for each test case, the maximum mark you can get.
Sample Input
3 1 2 3 1 2 3 3 1 2 3 3 2 1
Sample Output
6 9
Hint
We can explain the second sample as this. First, erase 1, you get 6-1=5 marks. Then erase 2, you get 4-1=3 marks. You may notice that in the beginning, the two 2s are at positions 2 and 5, but at this time, they are at positions 1 and 4. At last erase 3, you get 2-1=1 marks. Therefore, in total you get 5+3+1=9 and that is the best strategy.
【分析】
比较水的一道题,根据题意可知,任何两个区间仅为相交或包含的关系。
相交无论先删除哪一个对结果都没有影响,包含当然要先删除外面的那一个,所以从后往前删不会有包含的关系。
具体用树状数组实现就可以了。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <utility> 7 #include <iomanip> 8 #include <string> 9 #include <cmath> 10 #include <map> 11 12 const int MAXN = 100000 * 2 + 10; 13 using namespace std; 14 struct DATA{ 15 int l, r; 16 }num[MAXN * 2]; 17 int data[MAXN * 2]; 18 int C[MAXN * 2], cnt[MAXN * 2]; 19 int n; 20 bool get[MAXN * 2]; 21 22 int lowbit(int x){return x&-x;} 23 void add(int x, int val){ 24 while (x <= 2 * n){ 25 C[x] += val; 26 x += lowbit(x); 27 } 28 return; 29 } 30 int sum(int x){ 31 int cnt = 0; 32 while (x > 0){ 33 cnt += C[x]; 34 x -= lowbit(x); 35 } 36 return cnt; 37 } 38 void init(){ 39 C[0] = 0; 40 for (int i = 1; i <= 2 * n; i++) C[i] = cnt[i] = 0; 41 for (int i = 1; i <= 2 * n; i++){ 42 scanf("%d", &data[i]); 43 if (cnt[data[i]] == 0) {num[data[i]].l = i;cnt[data[i]]++;} 44 else num[data[i]].r = i; 45 add(i, 1); 46 } 47 long long Ans = 0; 48 memset(get, 0, sizeof(get)); 49 for (int i = 2 * n; i >= 1; i--){ 50 if (get[i] == 1) continue; 51 Ans += sum(i) - sum(num[data[i]].l); 52 add(i, -1); 53 add(num[data[i]].l, -1); 54 get[i] = get[num[data[i]].l] = 0; 55 } 56 printf("%lld\n", Ans); 57 } 58 59 int main(){ 60 int T = 0; 61 #ifdef LOCAL 62 freopen("data.txt", "r", stdin); 63 freopen("out.txt", "w", stdout); 64 #endif 65 while (scanf("%d", &n) != EOF){ 66 init(); 67 } 68 return 0; 69 } 70