1. 程式人生 > 其它 >Playoff Tournament (詳細版線段樹)

Playoff Tournament (詳細版線段樹)

k2 
k
  teams participate in a playoff tournament. The tournament consists of 2^k - 12 
k
 −1 games. They are held as follows: first of all, the teams are split into pairs: team 11 plays against team 22, team 33 plays against team 44 (exactly in this order), and so on (so, 2^{k-1}2 
k−1
  games are played 
in that phase). When a team loses a game, it is eliminated, and each game results in elimination of one team (there are no ties). After that, only 2^{k-1}2 k−1 teams remain. If only one team remains, it is declared the champion; otherwise, 2^{k-2}2 k−2 games are played: in the first one of them, the winner of the game "
11 vs 22" plays against the winner of the game "33 vs 44", then the winner of the game "55 vs 66" plays against the winner of the game "77 vs 88", and so on. This process repeats until only one team remains. For example, this picture describes the chronological order of games with k = 3k=3: Let the
string ss consisting of 2^k - 12 k −1 characters describe the results of the games in chronological order as follows: if s_is i ​ is 0, then the team with lower index wins the ii-th game; if s_is i ​ is 1, then the team with greater index wins the ii-th game; if s_is i ​ is ?, then the result of the ii-th game is unknown (any team could win this game). Let f(s)f(s) be the number of possible winners of the tournament described by the string ss. A team ii is a possible winner of the tournament if it is possible to replace every ? with either 1 or 0 in such a way that team ii is the champion. You are given the initial state of the string ss. You have to process qq queries of the following form: pp cc — replace s_ps p ​ with character cc, and print f(s)f(s) as the result of the query. Input The first line contains one integer kk (1 \le k \le 181≤k≤18). The second line contains a string consisting of 2^k - 12 k −1 characters — the initial state of the string ss. Each character is either ?, 0, or 1. The third line contains one integer qq (1 \le q \le 2 \cdot 10^51≤q≤210 5 ) — the number of queries. Then qq lines follow, the ii-th line contains an integer pp and a character cc (1 \le p \le 2^k - 11≤p≤2 k −1; cc is either ?, 0, or 1), describing the ii-th query. Output For each query, print one integer — f(s)f(s).
View problem

思路:

  • 這道題乍一看有分治的思想
  • 為了方便處理就利用線段樹(每一個節點可以儲存很多資訊,這就是他的魅力,應付各種型別的題)
  • 具體處理: 每一個節點要儲存 左兒子的真實值 和右兒子的真實值,和自己的真實值(更具0,1,?)
  • 如何將 0,1,?弄到對應的節點上呢?利用我下面這個建樹的方式 (i<<1,i<<1|1)

 可以看到這個是非常有規律的,每一層的長度和最左邊的值和上面一層2倍關係,具體處理看程式碼

#include <bits/stdc++.h>
using namespace std;
#define ri register int 
#define M 302144

template <class G> void read(G &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return ;
}

struct dain{
    int l,r;
    int val[5];// 左,右,2個,真實值。 
    char bj;
    int flag;
}p[M*4];
int n,cur;
char  s[M];

int num[M*4];
void build(int l,int r,int i)
{
    int mid=(l+r)>>1;
    p[i].l=l;p[i].r=r;
    if(l==r) 
    {
        p[i].val[4]=1;
        return ;
    }
    num[p[i].flag]=r;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    p[i].val[1]=p[i<<1].val[4];
    p[i].val[2]=p[i<<1|1].val[4];
    p[i].val[3]=p[i].val[1]+p[i].val[2];
    if(p[i].bj=='0') p[i].val[4]=p[i<<1].val[4];
    if(p[i].bj=='1') p[i].val[4]=p[i<<1|1].val[4];
    if(p[i].bj=='?') p[i].val[4]=p[i].val[1]+p[i].val[2];
}
char c;
void qu(int i,int a)
{
    if(p[i].flag==a)
    {
        p[i].bj=c;
        if(c=='0')
        {
            p[i].val[4]=p[i].val[1];
            return ;
        }
        if(c=='1'){
            p[i].val[4]=p[i].val[2];
            return ;
        } 
        if(c=='?'){ 
        p[i].val[4]=p[i].val[3];
        return ;
        } 
    }
    int mid=(p[i].r+p[i].l)>>1;
    if(num[a]<=mid)
    {
        qu(i<<1,a);
    }
    else
    {
        qu(i<<1|1,a);
    }
    p[i].val[1]=p[i<<1].val[4];
    p[i].val[2]=p[i<<1|1].val[4];
    p[i].val[3]=p[i].val[1]+p[i].val[2];
    if(p[i].bj=='0') p[i].val[4]=p[i<<1].val[4];
    if(p[i].bj=='1') p[i].val[4]=p[i<<1|1].val[4];
    if(p[i].bj=='?') p[i].val[4]=p[i].val[1]+p[i].val[2];    
}
int m;
int main(){
    
    read(n);
    for(ri i=1;i<(1<<n);i++)
    {
        cin>>s[i];
    }
    read(m);
    cur=0;
    for(ri i=(1<<(n-1));i>=1;i>>=1)
    {
        for(ri j=i;j<i*2;j++)
        {
            p[j].flag=++cur;
            p[j].bj=s[cur];
        }
    }
    build(1,(1<<n),1);
    
    for(ri i=1;i<=m;i++)
    {
        int a;
        cin>>a>>c;
        qu(1,a);
        printf("%d\n",p[1].val[4]);
    }
    return 0;
}
View Code

 後記:

  • 如何更具題目來建立樹,和相關的轉移,修改,是很重要的實現能力。