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≤2⋅10 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).
思路:
- 这道题乍一看有分治的思想
- 为了方便处理就利用线段树(每一个节点可以存储很多信息,这就是他的魅力,应付各种类型的题)
- 具体处理: 每一个节点要存储 左儿子的真实值 和右儿子的真实值,和自己的真实值(更具0,1,?)
- 如何将 0,1,?弄到对应的节点上呢?利用我下面这个建树的方式 (i<<1,i<<1|1)
7 那里是 111, 写彪了 qwq
可以看到这个是非常有规律的,每一层的长度和最左边的值和上面一层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; }
后记:
- 如何更具题目来建立树,和相关的转移,修改,是很重要的实现能力。