线段树
来源:互联网 发布:php开源网站源码 编辑:程序博客网 时间:2024/05/17 04:20
Accept: 11 Submit: 64
Time Limit: 10000 mSec Memory Limit : 262144 KB
Problem Description
Given N integers A={A[0],A[1],...,A[N-1]}. Here we have some operations:
Operation 1: AND opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] AND opn (here "AND" is bitwise operation).
Operation 2: OR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] OR opn (here "OR" is bitwise operation).
Operation 3: XOR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] XOR opn (here "XOR" is bitwise operation).
Operation 4: SUM L R
We want to know the result of A[L]+A[L+1]+...+A[R].
Now can you solve this easy problem?
Input
The first line of the input contains an integer T, indicating the number of test cases. (T≤100)
Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.
Then one line follows n integers A[0], A[1], ..., A[n-1] (0≤A[i]<16,0≤i<n).
Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)
Output
Sample Input
Sample Output
Hint
A = [1 2 4 7]
SUM 0 2, result=1+2+4=7;
XOR 5 0 0, A=[4 2 4 7];
OR 6 0 3, A=[6 6 6 7];
SUM 0 2, result=6+6+6=18.
Cached at 2012-12-03 14:54:45.
解题思路:数最大为15于是可以统计2进制的个数。线段树主要是Down的时候要考虑,对于每个二进制位我考虑4种操作:&0 -> 0, |1 -> R-L+1, ^1 -> R-L+1-cnt, 其他为不变。
则代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <cstring>using namespace std;const int ROOT = 1;const int MAXN = 1000010;struct Node{ int L, R; int cnt[4], op[4]; Node(int L =0, int R =0): L(L), R(R) { memset(op, -1, sizeof(op)); }};Node node[4*MAXN];int num[MAXN];inline int pL(int x) { return x<<1; }inline int pR(int x) { return (x<<1)|1; }void BuildTree(int L, int R, int root){ node[root] = Node(L, R); if (L == R) { for ( int i =0; i < 4; ++i) node[root].cnt[i] = num[L]&(1<<i) ? 1 : 0; return; } int M = (L+R)>>1; BuildTree(L, M, pL(root)); BuildTree(M+1, R, pR(root)); for ( int i =0; i < 4; i++) node[root].cnt[i] = node[pL(root)].cnt[i] + node[pR(root)].cnt[i];}inline int Cnt(Node &n, int i) { return n.op[i]==0 ? 0 : n.op[i]==1 ? n.R-n.L+1 : n.op[i]==2 ? n.R-n.L+1-n.cnt[i] : n.cnt[i]; }void Update(int root) { Node &n = node[root]; if (n.L == n.R) for ( int i =0; i < 4; n.op[i++] = -1) n.cnt[i] = Cnt(n, i); else for ( int i =0; i < 4; n.op[i++] = -1) n.cnt[i] = Cnt(node[pL(root)], i) + Cnt(node[pR(root)], i);}void Down(int root){ Node &n = node[root]; if (n.L != n.R) { Node &lc = node[pL(root)], &rc = node[pR(root)]; for ( int i =0; i < 4; ++i) if (n.op[i] == 0 || n.op[i] == 1) lc.op[i] = rc.op[i] = n.op[i]; else if (n.op[i] == 2) lc.op[i] = lc.op[i]==-1 ? 2 : 2-lc.op[i]-1, rc.op[i] = rc.op[i]==-1 ? 2 : 2-rc.op[i]-1; }}void Sunshine(int L, int R, int p, int m, int root){ Node &n = node[root]; Down(root); if (L==n.L && R==n.R) { Update(root); if (p == 0) for ( int i =0; i < 4; ++i) n.op[i] = (m & (1<<i))==0 ? 0 : -1; else if (p == 1) for ( int i =0; i < 4; ++i) n.op[i] = (m & (1<<i)) ? 1 : -1; else if (p == 2) for ( int i =0; i < 4; ++i) n.op[i] = (m & (1<<i)) ? 2 : -1; return; } Node &lc = node[pL(root)], &rc = node[pR(root)]; if (R <= lc.R) Sunshine(L, R, p, m, pL(root)); else if (L >= rc.L) Sunshine(L, R, p, m, pR(root)); else { Sunshine(L, lc.R, p, m, pL(root)); Sunshine(rc.L, R, p, m, pR(root)); } Update(root);}int Sum(Node &n){ int res = 0; for ( int i =0; i < 4; ++i) res += Cnt(n, i) << i; return res;}int Query(int L, int R, int root){ Node &n = node[root]; Down(root); Update(root); if (n.L==L && n.R==R) return Sum(n); Node &lc = node[pL(root)], &rc = node[pR(root)]; if (R <= lc.R) return Query(L, R, pL(root)); if (L >= rc.L) return Query(L, R, pR(root)); return Query(L, lc.R, pL(root)) + Query(rc.L, R, pR(root));}void Print(int root){ Node &n = node[root]; printf("L: %d, R: %d, %d, %d, %d, %d..\n", n.L, n.R, n.cnt[0], n.cnt[1], n.cnt[2], n.cnt[3]); for ( int i =0; i < 4; i++) cout << n.op[i] << " "; cout << endl; if (n.L == n.R) return; Print(pL(root)); Print(pR(root));}int main(){ freopen("h:\\data.in", "r", stdin); freopen("h:\\data.out", "w", stdout); int T, n, m, a, b, c, op; for ( scanf("%d", &T); T--; ) { scanf("%d%d", &n, &m); for ( int i =0; i < n; ++i) scanf("%d", num+i); BuildTree(0, n-1, ROOT); for ( char s[20]; m--; ) { scanf("%s%d%d", s, &a, &b); if (strcmp(s, "SUM") == 0) { printf("%d\n", Query(a, b, ROOT)); continue; } scanf("%d", &c); op = strcmp(s, "AND")==0 ? 0 : strcmp(s, "OR")==0 ? 1 : 2; Sunshine(b, c, op, a, ROOT); } } return 0;}
- 线段树?线段树!
- 线段树?线段树!
- 线段_线段树
- 线段_线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 加密算法之BLOWFISH算法
- Android 类似IPhone图片点击效果实现,点击logo变暗
- 经济学人:科技业四巨头上演“权力的游戏”
- Android MediaPlayer状态图明晰注释
- Android调用so文件(C代码库)方法详解
- 线段树
- 怎样评判SEO的工作好坏标准
- uboot之start.s分析
- Java 分页功能
- Makefile批处理
- 跑动的区域
- eclipse提示框的背景颜色设置
- fopen 提前 EOF
- C# 多线程编程 ThreadStart ParameterizedThreadStart