線段樹 初探

線段樹 初探



[kuangbin帶你飛]專題七 線段樹

A HDU 1166 敵兵佈陣

Problem Description

C國的死對頭A國這段時間正在進行軍事演習,所以C國間諜頭子Derek和他手下Tidy又開始忙乎了。A國在海岸線沿直線佈置了N個工兵營地,Derek和Tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數C國都掌握的一清二楚,每個工兵營地的人數都有可能發生變動,可能增加或減少若干人手,但這些都逃不過C國的監視。
中央情報局要研究敵人究竟演習什麼戰術,所以Tidy要隨時向Derek彙報某一段連續的工兵營地一共有多少人,例如Derek問:“Tidy,馬上彙報第3個營地到第10個營地共有多少人!”Tidy就要馬上開始計算這一段的總人數並彙報。但敵兵營地的人數經常變動,而Derek每次詢問的段都不一樣,所以Tidy不得不每次都一個一個營地的去數,很快就精疲力盡了,Derek對Tidy的計算速度越來越不滿:"你個死肥仔,算得這麼慢,我炒你魷魚!”Tidy想:“你自己來算算看,這可真是一項累人的工作!我恨不得你炒我魷魚呢!”無奈之下,Tidy只好打電話向計算機專家Windbreaker求救,Windbreaker說:“死肥仔,叫你平時做多點acm題和看多點算法書,現在嚐到苦果了吧!”Tidy說:"我知錯了。。。"但Windbreaker已經掛掉電話了。Tidy很苦惱,這麼算他真的會崩潰的,聰明的讀者,你能寫個程序幫他完成這項工作嗎?不過如果你的程序效率不夠高的話,Tidy還是會受到Derek的責罵的.

Input

第一行一個整數T,表示有T組數據。
每組數據第一行一個正整數N(N<=50000),表示敵人有N個工兵營地,接下來有N個正整數,第i個正整數ai代表第i個工兵營地裏開始時有ai個人(1<=ai<=50)。
接下來每行有一條命令,命令有4種形式:
(1) Add i j,i和j爲正整數,表示第i個營地增加j個人(j不超過30)
(2)Sub i j ,i和j爲正整數,表示第i個營地減少j個人(j不超過30);
(3)Query i j ,i和j爲正整數,i<=j,表示詢問第i到第j個營地的總人數;
(4)End 表示結束,這條命令在每組數據最後出現;
每組數據最多有40000條命令

Output

對第i組數據,首先輸出“Case i:”和回車,
對於每個Query詢問,輸出一個整數並回車,表示詢問的段中的總人數,這個數保持在int以內。
Sample Input
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
Sample Output
Case 1:
6
33
59


代碼

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N=5e4+5;

struct S
{
    int l;//左端點
    int r;//右端點
    int ans;//需要維護的內容
} tree[4*N];//線段樹需要開4倍

//建樹
void build(int l,int r,int k)
{
    tree[k].l=l;
    tree[k].r=r;
    if(l==r)//葉子節點
    {
        scanf("%d",&tree[k].ans);
        return ;
    }
    int m=(l+r)/2;
    build(l,m,k*2);//左孩子
    build(m+1,r,k*2+1);//右孩子
    tree[k].ans=tree[k*2].ans+tree[k*2+1].ans;//狀態合併,根據題意維護
}

int ans;

//單點修改
void add(int pos,int k,int b)
{
    if(tree[k].l==tree[k].r)//找到目標位置
    {
        tree[k].ans+=b;
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(pos<=m)
        add(pos,k*2,b);
    else
        add(pos,k*2+1,b);
	//所有包含結點k的結點狀態更新(需要維護的內容)
    tree[k].ans=tree[k*2].ans+tree[k*2+1].ans;//所有包含結點k的結點狀態更新
}

//區間查詢
void sum(int x,int y,int k)
{
    if(tree[k].l>=x&&tree[k].r<=y)
    {
        ans+=tree[k].ans;
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(x<=m)
        sum(x,y,k*2);
    if(y>m)
        sum(x,y,k*2+1);
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        int n;
        scanf("%d",&n);
        build(1,n,1);
        char str[10];
        printf("Case %d:\n",cas);
        while(scanf("%s",str)!=EOF&&str[0]!='E')
        {
            if(str[0]=='Q')
            {
                int l,r;
                ans=0;
                scanf("%d%d",&l,&r);
                sum(l,r,1);
                printf("%d\n",ans);
            }
            else if(str[0]=='A')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,1,y);
            }
            else if(str[0]=='S')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,1,-y);
            }
//            for(int i=1;i<=4*n;i++)
//            {
//                cout<<i<<"\t"<<tree[i].ans<<"\t"<<tree[i].l<<"\t"<<tree[i].r<<endl;
//            }
        }
    }
    return 0;
}

B HDU 1754 I Hate It

Problem Description

很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。
這讓很多學生很反感。
不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫一個程序,模擬老師的詢問。當然,老師有時候需要更新某位同學的成績。

Input

本題目包含多組測試,請處理到文件結束。
在每個測試的第一行,有兩個正整數 N 和 M ( 0<N<=200000,0<M<5000 ),分別代表學生的數目和操作的數目。
學生ID編號分別從1編到N。
第二行包含N個整數,代表這N個學生的初始成績,其中第i個數代表ID爲i的學生的成績。
接下來有M行。每一行有一個字符 C (只取’Q’或’U’) ,和兩個正整數A,B。
當C爲’Q’的時候,表示這是一條詢問操作,它詢問ID從A到B(包括A,B)的學生當中,成績最高的是多少。
當C爲’U’的時候,表示這是一條更新操作,要求把ID爲A的學生的成績更改爲B。

Output

對於每一次詢問操作,在一行裏面輸出最高成績。

Sample Input

5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5

Sample Output

5
6
5
9


代碼

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N=2e5+5;

struct S
{
    int l;//左端點
    int r;//右端點
    int ans;//需要維護的內容
} tree[4*N];//線段樹需要開4倍

//建樹
void build(int l,int r,int k)
{
    tree[k].l=l;
    tree[k].r=r;
    if(l==r)//葉子節點
    {
        scanf("%d",&tree[k].ans);
        return ;
    }
    int m=(l+r)/2;
    build(l,m,k*2);//左孩子
    build(m+1,r,k*2+1);//右孩子
    tree[k].ans=max(tree[k*2].ans,tree[k*2+1].ans);//狀態合併,根據題意維護
}

int ans;

//單點修改
void add(int pos,int k,int b)
{
    if(tree[k].l==tree[k].r)//找到目標位置
    {
        tree[k].ans=b;
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(pos<=m)
        add(pos,k*2,b);
    else
        add(pos,k*2+1,b);
    //所有包含結點k的結點狀態更新(需要維護的內容)
    tree[k].ans=max(tree[k*2].ans,tree[k*2+1].ans);//所有包含結點k的結點狀態更新
}

//區間查詢
void sum(int x,int y,int k)
{
    if(tree[k].l>=x&&tree[k].r<=y)
    {
        ans=max(ans,tree[k].ans);
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(x<=m)
        sum(x,y,k*2);
    if(y>m)
        sum(x,y,k*2+1);
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,n,1);
        char str[10];
//        printf("Case %d:\n",cas);
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='Q')
            {
                int l,r;
                ans=0;
                scanf("%d%d",&l,&r);
                sum(l,r,1);
                printf("%d\n",ans);
            }
            else if(str[0]=='U')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,1,y);
            }
//            for(int i=1;i<=4*n;i++)
//            {
//                cout<<i<<"\t"<<tree[i].ans<<"\t"<<tree[i].l<<"\t"<<tree[i].r<<endl;
//            }
        }
    }
    return 0;
}


C POJ 3468 A Simple Problem with Integers

Description

You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.


代碼


#include <cstdio>
#include <iostream>

using namespace std;

typedef long long ll;

const int N=2e5+5;

struct S
{
    int l,r;
    ll w;//需要維護的內容
    ll laz;//lazy標記
} tree[4*N];//開4倍數組

//建樹
void build(int k,int l,int r)
{
    tree[k].l=l,tree[k].r=r;
    if(tree[k].l==tree[k].r)
    {
        scanf("%lld",&tree[k].w);//也可以傳入葉節點的值
        return;
    }
    int m=(l+r)/2;
    build(k*2,l,m);
    build(k*2+1,m+1,r);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//狀態合併,維護內容
}

//lazy標記下傳
void down(int k)
{
    tree[k*2].laz+=tree[k].laz;
    tree[k*2+1].laz+=tree[k].laz;
    tree[k*2].w+=tree[k].laz*(tree[k*2].r-tree[k*2].l+1);
    tree[k*2+1].w+=tree[k].laz*(tree[k*2+1].r-tree[k*2+1].l+1);
    tree[k].laz=0;
}

ll ans=0;

//區間查詢,a,b爲查詢區間
void ask_interval(int a,int b,int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        ans+=tree[k].w;
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        ask_interval(a,b,k*2);
    if(b>m)
        ask_interval(a,b,k*2+1);
}

//區間修改,a,b爲修改的區間,y爲修改的值
void change_interval(int a,int b,ll y,int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w+=(tree[k].r-tree[k].l+1)*y;
        tree[k].laz+=y;
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        change_interval(a,b,y,k*2);
    if(b>m)
        change_interval(a,b,y,k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}

int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    build(1,1,n);
    while(q--)
    {
        char ch[3];
        scanf("%s",ch);
        if(ch[0]=='Q')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            ans=0;
            ask_interval(x,y,1);
            printf("%lld\n",ans);
        }
        else
        {
            int x,y;
            ll k;
            scanf("%d%d%lld",&x,&y,&k);
            change_interval(x,y,k,1);
        }
    }
    return 0;
}


D POJ 2528 Mayor’s posters

Description

The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for placing the posters and introduce the following rules:
Every candidate can place exactly one poster on the wall.
All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in Bytetown).
The wall is divided into segments and the width of each segment is one byte.
Each poster must completely cover a contiguous number of wall segments.
They have built a wall 10000000 bytes long (such that there is enough place for all candidates). When the electoral campaign was restarted, the candidates were placing their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in Bytetown was curious whose posters will be visible (entirely or in part) on the last day before elections.
Your task is to find the number of visible posters when all the posters are placed given the information about posters’ size, their place and order of placement on the electoral wall.

Input

The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers li and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= li <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered li, li+1 ,… , ri.

Output

For each input data set print the number of visible posters after all the posters are placed.
The picture below illustrates the case of the sample input.
在這裏插入圖片描述

Sample Input

1
5
1 4
2 6
8 10
3 4
7 10

Sample Output

4


代碼

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

typedef long long ll;

const int N=20005;

int ans;
int l[N],r[N];
int all[4*N];
int vis[4*N];
int cnt=0;

struct S
{
    int l,r;
    int w;//需要維護的內容
    int laz;//lazy標記
} tree[16*N];//開4倍數組

//建樹
void build(int k,int ll,int rr)
{
    tree[k].l=ll,tree[k].r=rr;
	tree[k].laz=0;
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=0;
        return;
    }
    int m=(ll+rr)/2;
    build(k*2,ll,m);
    build(k*2+1,m+1,rr);
    tree[k].w=0;//狀態合併,維護內容
}

//lazy標記下傳
void down(int k)
{
    tree[k*2].laz=tree[k].laz;
    tree[k*2+1].laz=tree[k].laz;
    tree[k*2].w=tree[k].laz;
    tree[k*2+1].w=tree[k].laz;
//    tree[k].w=0;
    tree[k].laz=0;
}

//區間查詢,a,b爲查詢區間
void ask_interval(int a,int b,int k)
{
    if(tree[k].l>=a&&tree[k].r<=b&&tree[k].l==tree[k].r)
    {
        if(vis[tree[k].w]==0&&tree[k].w!=0)
        {
            vis[tree[k].w]=1;
            cnt++;
        }
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        ask_interval(a,b,k*2);
    if(b>m)
        ask_interval(a,b,k*2+1);
}

//區間修改,a,b爲修改的區間,y爲增加的值
void change_interval(int a,int b,int y,int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w=y;
        tree[k].laz=y;
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        change_interval(a,b,y,k*2);
    if(b>m)
        change_interval(a,b,y,k*2+1);
    tree[k].w=0;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        int n;
        scanf("%d",&n);
        build(1,1,4*n);
        cnt=0;
        for(int i=1;i<=n;i++)
        {
            int li,ri;
            scanf("%d%d",&li,&ri);
            l[i]=li;
            r[i]=ri;
            all[i*2]=li;
            all[i*2-1]=ri;
        }
        sort(all+1,all+2*n+1);
        int counter=unique(all+1,all+2*n+1)-all-1;
        int m=counter;
        for(int i=2;i<=m;i++)
        {
            if(all[i]-all[i-1]>1&&all[i]-all[i-1]!=0)
                all[++counter]=all[i]-1;
        }
        sort(all+1,all+counter+1);
        for(int i=1;i<=n;i++)
        {
            int li=lower_bound(all+1,all+counter+1,l[i])-all;
            int ri=lower_bound(all+1,all+counter+1,r[i])-all;
            change_interval(li,ri,i,1);
        }
        ask_interval(1,2*n+counter,1);
        printf("%d\n",cnt);
    }
    return 0;
}


E HDU 1698 Just a Hook

Problem Description

In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.
在這裏插入圖片描述
Now Pudge wants to do some operations on the hook.
Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:
For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.
Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.

Output

For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.

Sample Input

1
10
2
1 5 2
5 9 3

Sample Output

Case 1: The total value of the hook is 24.


代碼

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=b;i>=a;i--)

const int N=1e5+5;
const double PI=acos(-1);
const ll MOD=1e9+7;
const double EPS=1e-9;

ll ans;

struct node
{
    int l,r;
    int w;
    int laz;//lazy標記
} tree[4*N];//開4倍數組

//建樹
void build(int k,int ll,int rr)
{
    tree[k].l=ll,tree[k].r=rr;
	tree[k].laz=0;
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=1;
        return;
    }
    int m=(ll+rr)/2;
    build(k*2,ll,m);
    build(k*2+1,m+1,rr);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//狀態合併,維護內容
}

//lazy標記下傳
void down(int k)
{
    tree[k*2].laz=tree[k].laz;
    tree[k*2+1].laz=tree[k].laz;
    tree[k*2].w=tree[k].laz*(tree[k*2].r-tree[k*2].l+1);
    tree[k*2+1].w=tree[k].laz*(tree[k*2+1].r-tree[k*2+1].l+1);
    tree[k].laz=0;
}

//單點查詢,pos爲查詢的點
void ask_point(int pos,int k)
{
    if(tree[k].l==tree[k].r)
    {
        ans=tree[k].w;
        return ;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(pos<=m)
        ask_point(pos,k*2);
    else
        ask_point(pos,k*2+1);
}

//單點修改,pos爲修改的點,y爲修改的值
void change_point(int pos,int k,int y)
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=y;
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(pos<=m)
        change_point(pos,k*2,y);
    else
        change_point(pos,k*2+1,y);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//維護
}

//區間查詢,a,b爲查詢區間
void ask_interval(int a,int b,int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        ans+=tree[k].w;
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        ask_interval(a,b,k*2);
    if(b>m)
        ask_interval(a,b,k*2+1);
}

//區間修改,a,b爲修改的區間,y爲增加的值
void change_interval(int a,int b,int y,int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w=(tree[k].r-tree[k].l+1)*y;
        tree[k].laz=y;
        return;
    }
    if(tree[k].laz)
        down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m)
        change_interval(a,b,y,k*2);
    if(b>m)
        change_interval(a,b,y,k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}

int main()
{
    int T;
    scanf("%d",&T);
    rep(cas,1,T)
    {
        ans=0;
        int n;
        scanf("%d",&n);
        build(1,1,n);
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            change_interval(x,y,z,1);
        }
        ask_interval(1,n,1);
//        printf("%lld\n",ans);
        printf("Case %lld: The total value of the hook is %lld.\n",cas,ans);
    }
    return 0;
}



其他

Codeforces Round #197 (Div. 2) 339D

Problem Description

Xenia the beginner programmer has a sequence a, consisting of 2n non-negative integers: a1, a2, …, a2n. Xenia is currently studying bit operations. To better understand how they work, Xenia decided to calculate some value v for a.
Namely, it takes several iterations to calculate value v. At the first iteration, Xenia writes a new sequence a1 or a2, a3 or a4, …, a^2n - 1^ or a2n, consisting of 2n - 1 elements. In other words, she writes down the bit-wise OR of adjacent elements of sequence a. At the second iteration, Xenia writes the bitwise exclusive OR of adjacent elements of the sequence obtained after the first iteration. At the third iteration Xenia writes the bitwise OR of the adjacent elements of the sequence obtained after the second iteration. And so on; the operations of bitwise exclusive OR and bitwise OR alternate. In the end, she obtains a sequence consisting of one element, and that element is v.
Let’s consider an example. Suppose that sequence a = (1, 2, 3, 4). Then let’s write down all the transformations (1, 2, 3, 4)  →  (1 or 2 = 3, 3 or 4 = 7)  →  (3 xor 7 = 4). The result is v = 4.
You are given Xenia’s initial sequence. But to calculate value v for a given sequence would be too easy, so you are given additional m queries. Each query is a pair of integers p, b. Query p, b means that you need to perform the assignment ap = b. After each query, you need to print the new value v for the new sequence a.

Input

The first line contains two integers n and m (1 ≤ n ≤ 17, 1 ≤ m ≤ 105). The next line contains 2n integers a1, a2, …, a2n (0 ≤ ai < 230). Each of the next m lines contains queries. The i-th line contains integers pi, bi (1 ≤ pi ≤ 2n, 0 ≤ bi < 230) — the i-th query.

Output

Print m integers — the i-th integer denotes value v for sequence a after the i-th query.

Examples

input
2 4
1 6 3 5
1 4
3 4
1 2
1 2

output

1
3
3
3


代碼

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N=2e5+5;

struct S
{
    int l;
    int r;
    int ans;
    int loop;
} tree[4*N];

int build(int l,int r,int k)
{
    tree[k].l=l;
    tree[k].r=r;
    if(l==r)//葉子節點
    {
        scanf("%d",&tree[k].ans);
        tree[k].loop=1;
        return 1;
    }
    int m=(l+r)/2;
    int lop=build(l,m,k*2);//左孩子
    lop=build(m+1,r,k*2+1);//右孩子
    lop++;
    tree[k].loop=lop;
    if(lop%2==1)
        tree[k].ans=tree[k*2].ans^tree[k*2+1].ans;//狀態合併
    else
        tree[k].ans=tree[k*2].ans|tree[k*2+1].ans;//狀態合併
    return lop;

}

void add(int pos,int k,int b)
{
    if(tree[k].l==tree[k].r)//找到目標位置
    {
        tree[k].ans=b;
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(pos<=m)
        add(pos,k*2,b);
    else
        add(pos,k*2+1,b);
    if(tree[k].loop%2==0)
        tree[k].ans=tree[k*2].ans|tree[k*2+1].ans;//所有包含結點k的結點狀態更新
    else
        tree[k].ans=tree[k*2].ans^tree[k*2+1].ans;//所有包含結點k的結點狀態更新
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int nn=1;
    for(int i=0; i<n; i++)
    {
        nn*=2;
    }
    build(1,nn,1);
    while(m--)
    {
        int p,b;
        scanf("%d%d",&p,&b);
        add(p,1,b);
//        for(int i=1; i<=4*n; i++)
//        {
//            cout<<i<<"\t"<<tree[i].ans<<"\t"<<tree[i].l<<"\t"<<tree[i].r<<"\t"<<tree[i].loop<<endl;
//        }
        printf("%d\n",tree[1].ans);
    }
    return 0;
}

發佈了44 篇原創文章 · 獲贊 6 · 訪問量 4538
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章