给出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 }