codeforces 400E. Inna and Binary Logic 线段树

题目链接

给出n个数, 定义a[1][i]为这初始的n个数, 然后a[i][j] = a[i-1][j]&a[i-1][j-1], 这样就可以得到一个三角形一共n*(n-1)/2个数。

给出一种操作, 将a[1][x]这个位置的数换为y, 然后求换完之后的这n(n-1)/2个数的和。

很有意思的题, 这个题应该按位建线段树, 这样需要建18棵, 因为a[1][i]的最大值为1e5。

然后我们来看具体如何做, 我们来看一组数据:3 6 7, 换为二进制之后是下面这个样子。

0 1 1

1 1 0

1 1 1

我们先来算一算这三个数的值为多少, 3+6+7+2+6+2 = 26。

我们发现第一个数和第二个数&之后剩余的是2, 第二个数和第三个数&之后剩余的是6, 我们来观察二进制, 发现第一个数和第二个数的第二位的2个1是相邻的, 并且这一位换成10进制正好是2, 而第二个数和第三个数的第一位和第二位的两个1是相邻的, 换成10进制之后是6。

由此可以推断出, 如果是一个单独的1, 那么贡献就是1, 两个相邻的1贡献是2*3/2 = 3,n个相邻的1贡献就是n(n+1)/2。

那么我们建立线段树的时候就应该保存一个sum, prefix, 以及suffix, 具体的看代码。

 1 #include <iostream>
 2 #include <vector>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <cmath>
 7 #include <map>
 8 #include <set>
 9 #include <string>
10 #include <queue>
11 #include <stack>
12 #include <bitset>
13 using namespace std;
14 #define pb(x) push_back(x)
15 #define ll long long
16 #define mk(x, y) make_pair(x, y)
17 #define lson l, m, rt<<1
18 #define mem(a) memset(a, 0, sizeof(a))
19 #define rson m+1, r, rt<<1|1
20 #define mem1(a) memset(a, -1, sizeof(a))
21 #define mem2(a) memset(a, 0x3f, sizeof(a))
22 #define rep(i, n, a) for(int i = a; i<n; i++)
23 #define fi first
24 #define se second
25 typedef pair<int, int> pll;
26 const double PI = acos(-1.0);
27 const double eps = 1e-8;
28 const int mod = 1e9+7;
29 const int inf = 1061109567;
30 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
31 const int maxn = 1e5+5;
32 ll cal(ll val) {
33     return 1LL*val*(val+1)/2;
34 }
35 struct SegmentTree
36 {
37     ll sum[maxn<<2], pre[maxn<<2], suf[maxn<<2];
38     void pushUp(int rt, int m) {
39         sum[rt] = sum[rt<<1|1] + sum[rt<<1];
40         if(pre[rt<<1|1]&&suf[rt<<1]) {
41             sum[rt] += cal(pre[rt<<1|1]+suf[rt<<1])-cal(suf[rt<<1])-cal(pre[rt<<1|1]); 
42         }     
43         pre[rt] = pre[rt<<1];
44         suf[rt] = suf[rt<<1|1];
45         if(pre[rt] == m-(m>>1)) {
46             pre[rt] += pre[rt<<1|1];
47         }
48         if(suf[rt] == m>>1) {
49             suf[rt] += suf[rt<<1];
50         }
51     }
52     void update(int p, int val, int l, int r, int rt) {
53         if(l == r) {
54             sum[rt] = pre[rt] = suf[rt] = val;
55             return ;
56         }
57         int m = l+r>>1;
58         if(p<=m)
59             update(p, val, lson);
60         else
61             update(p, val, rson);
62         pushUp(rt, r-l+1);
63     }
64 }tree[18];
65 int main()
66 {
67     int cnt, n, m, x, y, a[20];
68     cin>>n>>m;
69     for(int i = 1; i<=n; i++) {
70         scanf("%d", &x);
71         cnt = 0;
72         while(x) {
73             a[cnt++] = x&1;
74             x>>=1;
75         }
76         for(int j = 0; j<cnt; j++) {
77             tree[j].update(i, a[j], 1, n, 1);
78         }
79     }
80     while(m--) {
81         scanf("%d%d", &x, &y);
82         cnt = 0;
83         mem(a);
84         while(y) {
85             a[cnt++] = y&1;
86             y>>=1;
87         }
88         ll ans = 0, mul = 1;
89         for(int i = 0; i<18; i++) {
90             tree[i].update(x, a[i], 1, n, 1);
91             ans += tree[i].sum[1]*mul;
92             mul*=2;
93         }
94         cout<<ans<<endl;
95     }
96     return 0;
97 }
原文地址:https://www.cnblogs.com/yohaha/p/5088942.html