省选模拟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;
}
posted @ 2022-03-25 22:00  Max_QAQ  阅读(47)  评论(0编辑  收藏  举报