cychester

BZOJ1106[POI2007]立方体大作战tet - 树状数组

描述

一个叫做立方体大作战的游戏风靡整个Byteotia。这个游戏的规则是相当复杂的,所以我们只介绍他的简单规
则:给定玩家一个有2n个元素的栈,元素一个叠一个地放置。这些元素拥有n个不同的编号,每个编号正好有两个
元素。玩家每次可以交换两个相邻的元素。如果在交换之后,两个相邻的元素编号相同,则将他们都从栈中移除,
所有在他们上面的元素都会掉落下来并且可以导致连锁反应。玩家的目标是用最少的步数将方块全部消除。

 

题解

我们首先能大胆猜测,如果两个相同元素中间有一个在只出现一次的元素, 那么需要交换一次。

接下来我们只要求出每种元素的区间内有几个只出现一次的元素。

一次扫过$2 * n$个元素, 如果这种元素在之前没有出现过, 那么把该位置值记为 $1$

如果这种元素已经出现过, 那么把之前出现过的位置值记为-1, 当前位置值记为$1$

利用前缀和快速求出同种元素构成区间中的值的和, 并计入答案。

最后输出答案 $\div$ 2

利用树状数组可以查询前缀和, 单点修改。

 

代码

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rd read()
 5 using namespace std;
 6  
 7 const int N = 1e6 + 1e5;
 8  
 9 int l[N], sum[N], n;
10  
11 int read() {
12     int X = 0, p = 1; char c = getchar();
13     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
14     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
15     return X * p;
16 }
17  
18 int lowbit(int x) {
19     return x & (-x);
20 }
21  
22 void add(int x, int d) {
23     for(; x <= 2 * n; x += lowbit(x)) sum[x] += d;
24 }
25  
26 int query(int x) {
27     int re = 0;
28     for(; x; x -= lowbit(x)) re += sum[x];
29     return re;
30 }
31  
32 int main()
33 {
34     n = rd;
35     int ans = 0;
36     for(int i = 1; i <= 2 * n; ++i) {
37         int x = rd;
38         if(l[x]) {
39             ans += query(i) - query(l[x]);
40             add(l[x], -2);
41             add(i, 1);
42         }
43         else {
44             add(i, 1);
45             l[x] = i;
46         }
47     }
48     printf("%d\n",ans >> 1);
49 }
View Code

 

posted on 2018-08-24 08:49  cychester  阅读(211)  评论(0编辑  收藏  举报

导航