light oj 1080 線段樹和樹狀陣列

life4711發表於2014-08-10

http://www.lightoj.com/volume_showproblem.php?problem=1080

Given a binary number, we are about to do some operations on the number. Two types of operations can be here.

'I i j'    which means invert the bit from i to j (inclusive)

'Q i'    answer whether the ith bit is 0 or 1

The MSB (most significant bit) is the first bit (i.e. i=1). The binary number can contain leading zeroes.

Input

Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a line containing a binary integer having length n (1 ≤ n ≤ 105). The next line will contain an integer q (1 ≤ q ≤ 50000) denoting the number of queries. Each query will be either in the form 'I i j' where i, j are integers and 1 ≤ i ≤ j ≤ n. Or the query will be in the form 'Q i' where i is an integer and 1 ≤ i ≤ n.

Output

For each case, print the case number in a single line. Then for each query 'Q i' you have to print 1 or 0 depending on the ith bit.

Sample Input

Output for Sample Input

2

0011001100

6

I 1 10

I 2 7

Q 2

Q 1

Q 7

Q 5

1011110111

6

I 1 10

I 2 7

Q 2

Q 1

Q 7

Q 5

Case 1:

0

1

1

0

Case 2:

0

0

0

1


題目大意:
                   給定一定長度的區間段,每一位數都由0或1組成,現在我們進行對一系列的子區間進行修改操作(1變為0,0變為1),和查詢操作:在翻轉多次後第n為是什麼數字。
解題思路:1,線段樹
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100006;
char s[maxn];
struct segementtree
{
    struct Tree
    {
        int l,r;
        char value;
        int flag;
    }tree[maxn*4];
    void push_down(int root)
    {
        if(tree[root].flag)
        {
            tree[root<<1].flag+=tree[root].flag;
            tree[root<<1|1].flag+=tree[root].flag;
            tree[root].flag=0;
        }
    }
    void build(int root,int l,int r)
    {
        tree[root].l=l;
        tree[root].r=r;
        tree[root].flag=0;
        if(l==r)
        {
            tree[root].value=s[l];
            return;
        }
        int mid=l+(r-l)/2;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
    }
    void update(int root,int l,int r)
    {
        if(l<=tree[root].l&&tree[root].r<=r)
        {
            tree[root].flag++;
            return;
        }
        push_down(root);
        int mid=tree[root].l+(tree[root].r-tree[root].l)/2;
        if(l<=mid)
            update(root<<1,l,r);
        if(mid<r)
            update(root<<1|1,l,r);
    }
    char query(int root,int l,int r)
    {
        if(l<=tree[root].l&&tree[root].r<=r)
        {
            if(tree[root].flag%2)
            {
                tree[root].flag=0;
                if(tree[root].value=='1')
                {
                    tree[root].value='0';
                    return tree[root].value;
                }
                else
                {
                    tree[root].value='1';
                    return tree[root].value;
                }
            }
            else
            {
                tree[root].flag=0;
                return tree[root].value;
            }
        }
        push_down(root);
        int mid=tree[root].l+(tree[root].r-tree[root].l)/2;
        if(l<=mid)
             return query(root<<1,l,r);
        else if(mid<r)
            return query(root<<1|1,l,r);
    }
}tr;
int main()
{
    int T,n,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        getchar();
        scanf("%s",s+1);
        int len=strlen(s+1);
        //printf("%d\n",len);
        tr.build(1,1,len);
        scanf("%d",&n);
        printf("Case %d:\n",++tt);
        while(n--)
        {
            char c[2];
            int x,y;
            scanf("%s",c);
            if(c[0]=='I')
            {
                scanf("%d%d",&x,&y);
                tr.update(1,x,y);
            }
            else
            {
                scanf("%d",&x);
                printf("%c\n",tr.query(1,x,x));
            }
        }
    }
    return 0;
}

2.樹狀陣列
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
const int maxn=110005;
int c[maxn],len;
int lowbit(int x)
{
    return (-x)&x;
}
int sum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x,int d)
{
    while(x<=len)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int main()
{
    int T,tt=0;
    char s[maxn];
    scanf("%d",&T);
    while(T--)
    {
        memset(c,0,sizeof(c));
        scanf("%s",s+1);
        len=strlen(s+1);
        int n;
        scanf("%d",&n);
        printf("Case %d:\n",++tt);
        while(n--)
        {
            char a[2];
            scanf("%s",a);
            if(a[0]=='I')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,1);
                add(y+1,-1);
            }
            else
            {
                int x;
                scanf("%d",&x);
                int t=sum(x);
                if(t&1)
                {
                    if(s[x]=='1')
                        printf("0\n");
                    else
                        printf("1\n");
                }
                else
                    printf("%c\n",s[x]);
            }
        }
    }
    return 0;
}

總結:對於這種區間的查詢和修改操作,基本上都是用線段樹和數裝陣列兩種方法來進行解決,線段樹的功能要比樹狀陣列的功能要大一些,但是樹狀陣列程式碼量較小。

相關文章