省选模拟38
A. 异或矩阵
不难发现每个位置的贡献方式是一个组合数
然后根据 \(Lucas\) 定理,我们 \(2^k\) 的转移,这样在 \(\text{mod 2}\) 意义下
只有 \(0\) 和 \(2^k\) 的位置有贡献
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,K,v;
uint a[3000010],b[3000010],ans;
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
n=read(),K=read()-1,a[1]=read();
for(int i=2;i<=n;i++) a[i]=1145141*a[i-1]+1919*i+810;
while(K){
v=K&-K;K-=v;n-=v;
for(int i=1;i<=n;i++) b[i]=a[i]^a[i+v];
for(int i=1;i<=n;i++) a[i]=b[i];
}
for(uint i=1;i<=n;i++) ans=ans+(1u*i*(a[i]^i));
printf("%u\n",ans);
return 0;
}
B. 树
分类讨论计算答案,分别是选择 \(lca\) 和不选
选的话子树内可以随便选,不选的话至少选择两个子树内的点
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 998244353
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n;
int f[100010][2],siz[100010],ans[100010],k2[100010];
int head[100010],ver[200010],to[200010],tot;
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
void dfs(int x,int fa){
siz[x]=1;
for(int i=head[x];i;i=to[i]){
int y=ver[i];if(y==fa) continue;
dfs(y,x);siz[x]+=siz[y];
f[x][1]=f[x][1]*k2[siz[y]]%mod;
(f[x][1]+=f[x][0]*(k2[siz[y]]-1)%mod)%=mod;
(f[x][0]+=k2[siz[y]]-1)%=mod;
}
ans[x]=(k2[siz[x]-1]+f[x][1])%mod;
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
k2[0]=1;for(int i=1;i<=100000;i++) k2[i]=k2[i-1]*2%mod;
n=read();
for(int i=1,x,y;i<n;i++){x=read(),y=read();add(x,y),add(y,x);}
dfs(1,0);
for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}
C. 黑白树
用线段树和树剖实现
线段树上只维护以区间 \(LCA\) 为颜色,且完全包含子区间的信息
于是需要判定是否是同一联通块,这样才能合并
对于判定是否是同一个颜色的联通块,可以根据从根到这个点的路径上异色点的个数来判断
然后线段树上每个节点维护从根到这个节点代表区间内的点的 \(lca\) 的颜色个数
对于每个同色联通块以最顶上的那个点来维护整个联通块
考虑如何找到这个点,树剖后对于每条重链维护每种颜色的点出现的深度
可以用 \(\text{set}\) 简单实现,查询时从当前点往上跳重链
然后二分出第一个比当前点深度小的异色点
再往这个点所在的子树走一步就是这个最顶上的点
这样修改时直接修改这个点的子树,在 \(\text{pushdown}\) 时,需要判定是否和子区间是同色的
然后 \(\text{query}\) 时也需要判定,剩下的两个操作可以直接做
Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m;
int col[200010],v[200010];
int head[200010],ver[400010],to[400010],tot;
int dfn[200010],id[200010],top[200010],siz[200010],fa[200010],son[200010],dep[200010],clo;
set<int>S[200010][2];
struct seg{int mx[2],s[2],atag[2],stag[2],btag;}st[200010*4];
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
void dfs1(int x,int fa,int dep){
::fa[x]=fa,::dep[x]=dep,siz[x]=1;
int maxson=-1;
for(int i=head[x];i;i=to[i]){
int y=ver[i];if(y==fa) continue;
dfs1(y,x,dep+1);siz[x]+=siz[y];
if(siz[y]>maxson) son[x]=y,maxson=siz[y];
}
}
void dfs2(int x,int topf){
dfn[x]=++clo;id[clo]=x;top[x]=topf;if(!son[x]) return ;
dfs2(son[x],topf);
for(int i=head[x];i;i=to[i]){
int y=ver[i];if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
inline void pushup(int rt){
for(int i=0;i<2;i++) st[rt].mx[i]=max(
(st[lson].s[i^1]==st[rt].s[i^1])?st[lson].mx[i]:-inf,
(st[rson].s[i^1]==st[rt].s[i^1])?st[rson].mx[i]:-inf
);
}
inline void pushdown(int rt){
if(st[rt].btag){
st[lson].btag+=st[rt].btag;st[rson].btag+=st[rt].btag;
for(int i=0;i<2;i++) st[lson].mx[i]+=st[rt].btag,st[rson].mx[i]+=st[rt].btag;
st[rt].btag=0;
}
for(int i=0;i<2;i++) if(st[rt].stag[i]){
st[lson].s[i]+=st[rt].stag[i];st[lson].stag[i]+=st[rt].stag[i];
st[rson].s[i]+=st[rt].stag[i];st[rson].stag[i]+=st[rt].stag[i];
st[rt].stag[i]=0;
}
for(int i=0;i<2;i++) if(st[rt].atag[i]){
if(st[lson].s[i^1]==st[rt].s[i^1]) st[lson].atag[i]+=st[rt].atag[i],st[lson].mx[i]+=st[rt].atag[i];
if(st[rson].s[i^1]==st[rt].s[i^1]) st[rson].atag[i]+=st[rt].atag[i],st[rson].mx[i]+=st[rt].atag[i];
st[rt].atag[i]=0;
}
}
void build(int rt,int l,int r){
if(l==r) return st[rt].mx[col[id[l]]]=v[id[l]],st[rt].mx[col[id[l]]^1]=-inf,void();
int mid=(l+r)>>1;pushdown(rt);
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void upds(int rt,int l,int r,int L,int R,int k,int opt){
if(L<=l&&r<=R) return st[rt].s[opt]+=k,st[rt].stag[opt]+=k,void();
int mid=(l+r)>>1;pushdown(rt);
if(L<=mid) upds(lson,l,mid,L,R,k,opt);
if(R>mid) upds(rson,mid+1,r,L,R,k,opt);
pushup(rt);
}
void upda(int rt,int l,int r,int L,int R,int k,int opt,int V){
if(L<=l&&r<=R) return st[rt].mx[opt]+=k,st[rt].atag[opt]+=k,void();
int mid=(l+r)>>1;pushdown(rt);
if(L<=mid&&st[lson].s[opt^1]<=V) upda(lson,l,mid,L,R,k,opt,V);
if(R>mid&&st[rson].s[opt^1]<=V) upda(rson,mid+1,r,L,R,k,opt,V);
pushup(rt);
}
void updb(int rt,int l,int r,int L,int R,int k){
if(L<=l&&r<=R) return st[rt].mx[0]+=k,st[rt].mx[1]+=k,st[rt].btag+=k,void();
int mid=(l+r)>>1;pushdown(rt);
if(L<=mid) updb(lson,l,mid,L,R,k);
if(R>mid) updb(rson,mid+1,r,L,R,k);
pushup(rt);
}
void updc(int rt,int l,int r,int pos){
if(l==r) return swap(st[rt].mx[0],st[rt].mx[1]),void();
int mid=(l+r)>>1;pushdown(rt);
if(pos<=mid) updc(lson,l,mid,pos);
else updc(rson,mid+1,r,pos);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R,int opt,int V){
if(L<=l&&r<=R) return st[rt].mx[opt];
int mid=(l+r)>>1,res=-inf;pushdown(rt);
if(L<=mid&&st[lson].s[opt^1]<=V) res=max(res,query(lson,l,mid,L,R,opt,V));
if(R>mid&&st[rson].s[opt^1]<=V) res=max(res,query(rson,mid+1,r,L,R,opt,V));
return res;
}
int querys(int rt,int l,int r,int pos,int opt){
if(l==r) return st[rt].s[opt];
int mid=(l+r)>>1;pushdown(rt);
if(pos<=mid) return querys(lson,l,mid,pos,opt);
else return querys(rson,mid+1,r,pos,opt);
}
inline void Tupd(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
updb(1,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
updb(1,1,n,dfn[x],dfn[y],k);
}
int getx(int x,int opt){
int now=top[x],lst=x,v;
while(now){
if(S[now][opt].size()&&*S[now][opt].begin()<=dep[x]){
v=*--S[now][opt].upper_bound(dep[x]);
if(v==dep[x]) return lst;
else return id[dfn[now]+v-dep[now]+1];
}
lst=now;x=fa[now];now=top[x];
}
return 1;
}
inline void rev(int x){
upds(1,1,n,dfn[x],dfn[x]+siz[x]-1,-1,col[x]);S[top[x]][col[x]].erase(dep[x]);col[x]^=1;
upds(1,1,n,dfn[x],dfn[x]+siz[x]-1, 1,col[x]);S[top[x]][col[x]].insert(dep[x]);
updc(1,1,n,dfn[x]);
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("astill.in","r",stdin);
freopen("astill.out","w",stdout);
n=read(),m=read();
for(int i=1,x,y;i<n;i++){x=read(),y=read();add(x,y),add(y,x);}
for(int i=1;i<=n;i++) col[i]=read();for(int i=1;i<=n;i++) v[i]=read();
dfs1(1,0,1),dfs2(1,1);
for(int i=1;i<=n;i++) upds(1,1,n,dfn[i],dfn[i]+siz[i]-1,1,col[i]);
for(int i=1;i<=n;i++) S[top[i]][col[i]].insert(dep[i]);
build(1,1,n);
for(int i=1,op,x,y,v;i<=m;i++){
op=read();
if(op==1){x=read();rev(x);}
if(op==2){
x=read();x=getx(x,col[x]^1);v=querys(1,1,n,dfn[x],col[x]^1);
upda(1,1,n,dfn[x],dfn[x]+siz[x]-1,read(),col[x],v);
}
if(op==3){
x=read();x=getx(x,col[x]^1);v=querys(1,1,n,dfn[x],col[x]^1);
printf("%d\n",query(1,1,n,dfn[x],dfn[x]+siz[x]-1,col[x],v));
}
if(op==4){x=read(),y=read();Tupd(x,y,read());}
if(op==5){x=read();updb(1,1,n,dfn[x],dfn[x]+siz[x]-1,read());}
}
return 0;
}