线段树

来源:互联网 发布:php开源网站源码 编辑:程序博客网 时间:2024/05/17 04:20
                                            Problem D Digits Count

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

For each test case and for each "SUM" operation, please output the result with a single line.

 Sample Input

14 41 2 4 7SUM 0 2XOR 5 0 0OR 6 0 3SUM 0 2

 Sample Output

718

 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.


Submit  Back  Status


解题思路:数最大为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;}




原创粉丝点击