P11234
树大小会变是很麻烦的事情,所以我们首先假设树大小固定,因为实际上我们可以枚举所有可能的树大小,复杂度也是线性的。
定义“时刻
一个显然的
但是这太慢了。所以我们来观察一些性质。
首先,一个人可能会成为最终胜者计入答案中,当且仅当他在所有比赛中都没有确定地被打败。
我们观察到一个人似乎是在某一个时刻之后被确定地打败的......也就是说,这个人会在一段时刻前缀被计入答案。我们尝试具体描述一下这个前缀到底长什么样。如果可以描述清楚,这个题就做完了。
具体分析一下可以看出,一个人在一次比赛中确定地被打败只有以下两种情况:
-
这个人不是擂主,而且他的兄弟子树有一个唯一的,已知能力值足够的胜者;
-
这个人是擂主,但能力值不够。
我们发现第二个条件是容易的:在这个人的能力值尚未确定的时候,他不会受到这个条件的限制;在这个人的能力值确定之后,他的能力值就需要至少是所有他参加的他是擂主的比赛的最大值。这个容易线性处理出所有限制,而且和时刻无关。
要想考虑第一个条件,我们就仔细考虑一下子树确定胜者相关的事情。
对于一个子树
也就是说,在
t_x 这个时刻,这个子树内的除了f_x 之外的所有人(无论其能力值是否确定),都已经确定会被打败。故显然f_x 不会改变。
那么,假如当前时刻为
好的!看来每个人贡献到答案的时刻确实是一个前缀(因为是很多个前缀的交),但是我们还不知道
我们考虑在树上 dp,那么
获胜的人是谁直接根据题意判一判就好。
因为一个人会参加
实现上,我们一遍 dfs 预处理出每个子树的
时间复杂度
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N ((1<<17)+5)
ll diff[N];
int fc[N<<1],tc[N<<1];
int a[N];
int n,m,Tc;
char tmp[N];
int D[N];
int A[N],c[N];
int K;
void dfs1(int x,int h){
if(!h){
fc[x]=a[x-(1<<K)+1];
tc[x]=x-(1<<K)+1;
return;
}
dfs1(x<<1,h-1);
dfs1(x<<1|1,h-1);
if(!D[x] && fc[x<<1]>=h)tc[x]=tc[x<<1];
else tc[x]=tc[x<<1|1];
fc[x]=fc[x<<1|(D[x]^(fc[(x<<1)|D[x]]<h))];
}
void dfs2(int x,int hi,int h,int L,int R){
if(L>R)return;
if(!h){
int v=x-(1<<K)+1;
if(L<min(R,v))diff[L]+=v,diff[min(R,v)]-=v;
if(a[v]>=hi && max(v,L)<R)diff[max(v,L)]+=v,diff[R]-=v;
return;
}
if(!D[x]){
dfs2(x<<1,max(hi,h),h-1,L,R);
dfs2(x<<1|1,hi,h-1,L,fc[x<<1]>=h?min(R,tc[x<<1]):R);
}
else{
dfs2(x<<1,hi,h-1,L,fc[x<<1|1]>=h?min(R,tc[x<<1|1]):R);
dfs2(x<<1|1,max(hi,h),h-1,L,R);
}
}
int main(){
freopen("arena.in","r",stdin);
freopen("arena.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&A[i]);
for(int i=1;i<=m;i++)scanf("%d",&c[i]);
K=__lg(n-1)+1;
for(int d=K-1;d>=0;d--){
scanf("%s",tmp);
for(int i=0;i<(1<<d);i++)D[i+(1<<d)]=tmp[i]-'0';
}
scanf("%d",&Tc);
while(Tc--){
int X[4];
scanf("%d%d%d%d",&X[0],&X[1],&X[2],&X[3]);
for(int i=1;i<=n;i++)a[i]=A[i]^X[i&3];
dfs1(1,K);
for(int i=0;i<=n;i++)diff[i]=0;
for(int d=0;d<=K;d++)dfs2(1<<(K-d),0,d,d==0?1:(1<<(d-1))+1,(1<<d)+1);
for(int i=1;i<=n;i++)diff[i]+=diff[i-1];
ll ans=0;
for(int i=1;i<=m;i++)ans^=i*diff[c[i]];
printf("%lld\n",ans);
}
return 0;
}