20260113模拟赛
20260113模拟赛
树的直径
枚举直径中点:
- 如果长度为奇数则中点是一条边权为 \(1\) 的边。
- 如果长度为偶数则中点是一条边权都是 \(0\) 的长链。
对偶数使用点边容斥,发现这条边在中间时如果边权为 \(0\) 要在偶数中容斥 \(-1\),如果是 \(1\) 要在奇数中加上 \(1\),贡献抵消了。所以现在要算的就是每个点在中心的直径条数。
枚举每个点为根,分别设 \(x\) 子树内最大深度为 \(i\) 的方案数/所有方案的点数之和,转移枚举边权是 max 卷积,注意根特殊考虑,要求两边长度相等。
考虑换根,max 卷积容易优化到 \(O(\max(a,b))\) 复杂度,每次求值时将所有子节点按最大深度从小到大排序依次合并,则复杂度是 \(O(n)\) 的因为 \(\sum dep=n\)。
每条边的左右两边分别会算一次,复杂度 \(O(n^2)\)。
广为人知
原题 P8257 [CTS2022] 普罗霍洛夫卡。
扫描线之后,求区间加一,历史区间异或和。考虑由于异或所以两个时刻相同则不会产生历史贡献。所以对奇偶时刻分别维护,问题变为:
- 每次 \(i\) 时刻给区间 \(j\in[l,r]\),令 \(a_j\) 加一,\(c_{i\bmod 2,j}\oplus a_j \oplus(a_j-1)\)。
- 每次询问 \(r\) 次操作后 \(\oplus_{i=l}^r c_{r\bmod 2,i}\) 是多少。
考虑 \(x\oplus(x+1)\) 是 \(2\) 的多少次方减一,即我们只关心 \(a_i\) 的最低位 \(0\)。取 \(B=2^k\) 根号分治,低位不同的数只有 \(B\) 种,高位的改变次数不超过 \(\frac n B\)。为了处理区间问题以 \(B\) 分块,每块维护上述信息,每次枚举贡献是 \(2^i\) 的数计算,复杂度 \(O(n\sqrt n \log n)\)。
60代码
const int MAXN=4e5;
const int blk_sz=256;
const int LOG_B=8;
int n,qu,lst[MAXN+5],a[MAXN+5],bel[MAXN+5];
int res[MAXN+5],ql[MAXN+5],qr[MAXN+5];
vector<pii>qv[MAXN+5];
struct block{
int L,R,len,b[blk_sz+5],c[2][blk_sz+5],tag,tot_xor[2];
int mark[2][LOG_B+1][blk_sz+2],cnt[LOG_B+1][blk_sz+2];
vector<int>vec[blk_sz+2];
void init(){
tag=0;
memset(mark,0,sizeof(mark));memset(cnt,0,sizeof(cnt));
for(int j=0;j<LOG_B;j++)cnt[j][0]=len;
for(int j=0;j<blk_sz;j++)vec[j].clear();
for(int j=1;j<=len;j++)vec[0].pb(j);
}
void add(int tim,int ql,int qr){
for(int o=0;o<2;o++)for(int k=1;k<=len;k++)for(int t=0;t<LOG_B;t++)
c[o][k]^=mark[o][t][b[k]&((1<<t+1)-1)];
for(int k=1;k<=len;k++)b[k]+=tag;
for(int k=ql;k<=qr;k++){
c[tim][k]^=(b[k]^(b[k]+1));
tot_xor[tim]^=(b[k]^(b[k]+1));
++b[k];
}
tag=0;
memset(mark,0,sizeof(mark));memset(cnt,0,sizeof(cnt));
for(int k=1;k<=len;k++)for(int t=0;t<LOG_B;t++)
cnt[t][b[k]&((1<<t+1)-1)]++;
for(int k=0;k<blk_sz;k++)vec[k].clear();
for(int k=1;k<=len;k++)vec[b[k]&(blk_sz-1)].pb(k);
}
void addwhole(int tim){
for(int t=0;t<LOG_B;t++){
int val=((1<<t)-1-tag)&((1<<t+1)-1);
mark[tim][t][val]^=((1<<t+1)-1);
if(cnt[t][val]&1)tot_xor[tim]^=((1<<t+1)-1);
}
for(int p:vec[(blk_sz-1-tag)&(blk_sz-1)]){
c[tim][p]^=(b[p]+tag)^(b[p]+tag+1);
tot_xor[tim]^=(b[p]+tag)^(b[p]+tag+1);
}
tag++;
}
int query(int tim,int ql,int qr){
int res=0;
for(int k=ql;k<=qr;k++){
res^=c[tim][k];
for(int t=0;t<LOG_B;t++)
res^=mark[tim][t][b[k]&((1<<t+1)-1)];
}return res;
}
int querywhole(int tim){return tot_xor[tim];}
}B[MAXN/blk_sz+5];
int main(){
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1,l,r;i<=qu;i++){scanf("%d%d",&l,&r);qv[r].pb(mp(l,i));}
for(int i=1;i<=n;i++)ql[i]=lst[a[i]]+1,qr[i]=i,lst[a[i]]=i;
int blk_cnt=(n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
int L=(i-1)*blk_sz+1,R=min(i*blk_sz,n);
B[i].L=L;B[i].R=R;B[i].len=R-L+1;
for(int j=L;j<=R;j++)bel[j]=i;
B[i].init();
}
for(int i=1;i<=n;i++){
int L=ql[i],R=qr[i];
if(bel[L]==bel[R]){
B[bel[L]].add(i&1,L-B[bel[L]].L+1,R-B[bel[L]].L+1);
}else{
B[bel[L]].add(i&1,L-B[bel[L]].L+1,B[bel[L]].len);
B[bel[R]].add(i&1,1,R-B[bel[R]].L+1);
for(int j=bel[L]+1;j<bel[R];j++)B[j].addwhole(i&1);
}
for(pii p:qv[i]){
L=p.fi;R=i;
if(bel[L]==bel[R]){
res[p.se]=B[bel[L]].query(i&1,L-B[bel[L]].L+1,R-B[bel[L]].L+1);
}else{
res[p.se]^=B[bel[L]].query(i&1,L-B[bel[L]].L+1,B[bel[L]].len);
res[p.se]^=B[bel[R]].query(i&1,1,R-B[bel[R]].L+1);
for(int j=bel[L]+1;j<bel[R];j++)res[p.se]^=B[j].querywhole(i&1);
}
}
}
for(int i=1;i<=qu;i++)printf("%d\n",res[i]);
return 0;
}
\(\log\) 在于枚举 \(2^i\) 贡献,考虑维护 \(coef_{tag}\) 表示考虑块中所有 \((a_i+tag)\oplus(a_i+tag+1)\) 的各个位的异或和之和,这样不带 \(\log\),这样的值有 \(2^k\) 级别个。求所有这个值考虑 \(x\) 模 \(2^k\) 下等于 \(d\),则模 \(2^{k+1}\) 下等于 \(d\) 或 \(d+2^k\),这类似线段树式的合并。
代码
const int MAXN=4e5;
const int blk_sz=256;
const int LOG_B=8;
int n,qu,lst[MAXN+5],a[MAXN+5],bel[MAXN+5],dep[blk_sz*2+5],rev[blk_sz+5];
int res[MAXN+5],ql[MAXN+5],qr[MAXN+5];
vector<pii>qv[MAXN+5];
struct block{
int L,R,len,b[blk_sz+5],c[2][blk_sz+5],tag,tot_xor[2];
int coef[blk_sz+5],tot[2][blk_sz+5],nw[blk_sz+5];
vector<int>vec[blk_sz+2];
void trans(int *f,int *g){
static int A[blk_sz*2+5],B[blk_sz*2+5];
for(int i=0;i<blk_sz;i++)A[rev[i]|blk_sz]=f[i];
for(int i=blk_sz-1;i;i--)A[i]=A[i<<1]^A[i<<1|1];
for(int i=1;i<=blk_sz*2-1;i++)B[i]=B[i>>1]^(A[i]<<dep[i]);
for(int i=0;i<blk_sz;i++)g[i]=B[rev[i]|blk_sz]^(f[i]*(blk_sz*2-1));
}
void pushdown(){
if(!tag)return;
for(int o=0;o<2;o++){
trans(tot[o],nw);
for(int k=1;k<=len;k++)c[o][k]^=nw[b[k]&(blk_sz-1)];
}
memset(tot,0,sizeof(tot));
for(int k=1;k<=len;k++)b[k]+=tag;
tag=0;
}
void rebuild(){
for(int k=0;k<blk_sz;k++)vec[k].clear();
for(int k=1;k<=len;k++)vec[b[k]&(blk_sz-1)].pb(k);
memset(coef,0,sizeof(coef));
static int tmp[blk_sz+5];
for(int k=0;k<blk_sz;k++)tmp[k]=vec[k].size()&1;
trans(tmp,coef);
}
void init(){tag=0;rebuild();}
void add(int tim,int ql,int qr){
pushdown();
for(int k=ql;k<=qr;k++){
c[tim][k]^=(b[k]^(b[k]+1));
tot_xor[tim]^=(b[k]^(b[k]+1));
++b[k];
}
rebuild();
}
void addwhole(int tim){
int val=(blk_sz-1-tag)&(blk_sz-1);
tot_xor[tim]^=coef[val];
tot[tim][val]^=1;
for(int p:vec[val]){
c[tim][p]^=(b[p]+tag)^(b[p]+tag+1);
tot_xor[tim]^=(b[p]+tag)^(b[p]+tag+1);
}
tag++;
}
int query(int tim,int ql,int qr){
if(tag)pushdown(),rebuild();
int res=0;
for(int k=ql;k<=qr;k++)res^=c[tim][k];
return res;
}
int querywhole(int tim){return tot_xor[tim];}
}B[MAXN/blk_sz+5];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&qu);
for(int i=0;i<blk_sz;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(LOG_B-1));
for(int i=2;i<blk_sz*2;i++)dep[i]=dep[i>>1]+1;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1,l,r;i<=qu;i++){scanf("%d%d",&l,&r);qv[r].pb(mp(l,i));}
for(int i=1;i<=n;i++)ql[i]=lst[a[i]]+1,qr[i]=i,lst[a[i]]=i;
int blk_cnt=(n-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
int L=(i-1)*blk_sz+1,R=min(i*blk_sz,n);
B[i].L=L;B[i].R=R;B[i].len=R-L+1;
for(int j=L;j<=R;j++)bel[j]=i;
B[i].init();
}
for(int i=1;i<=n;i++){
int L=ql[i],R=qr[i];
if(bel[L]==bel[R]){
B[bel[L]].add(i&1,L-B[bel[L]].L+1,R-B[bel[L]].L+1);
}else{
B[bel[L]].add(i&1,L-B[bel[L]].L+1,B[bel[L]].len);
B[bel[R]].add(i&1,1,R-B[bel[R]].L+1);
for(int j=bel[L]+1;j<bel[R];j++)B[j].addwhole(i&1);
}
for(pii p:qv[i]){
L=p.fi;R=i;
if(bel[L]==bel[R]){
res[p.se]=B[bel[L]].query(i&1,L-B[bel[L]].L+1,R-B[bel[L]].L+1);
}else{
res[p.se]^=B[bel[L]].query(i&1,L-B[bel[L]].L+1,B[bel[L]].len);
res[p.se]^=B[bel[R]].query(i&1,1,R-B[bel[R]].L+1);
for(int j=bel[L]+1;j<bel[R];j++)res[p.se]^=B[j].querywhole(i&1);
}
}
}
for(int i=1;i<=qu;i++)printf("%d\n",res[i]);
return 0;
}

浙公网安备 33010602011771号