20231014 模拟赛

A

题意:给定 \(n\) 个点的树,求有多少条子链使得不在链上的点离链的距离的最大值 \(\leq 1\)\(n\leq 2\times 10^5\)

考虑哪些边必须选,就是直接把度数为 \(1\) 的点删了之后,剩下的需要是一条链。如果不是,答案是 \(0\)。那么这条链上所有边必须选。

想要拓展的话,考虑这条链的端点即可。注意特判菊花图。

B

现在有一张有向图,这个有向图有 \(n\) 个节点,\(m\) 条有向边。需要回答 \(Q\) 组询问。对于每组询问,有两个正整数 \(i,j\)。你需要回答从 \(i\)\(j\) 的恰好经过 \(k\) 条连边的
路径数量。

\(n\leq 60\)

矩阵快速幂板子题。
矩阵快速幂板子题。
矩阵快速幂板子题。

C

好好好,不知道为啥交上去 CE 了。

应该是评测姬版本太低/oh

\(100\rightarrow 0\)

题意

首先知道 \(A \operatorname{nand} B=\operatorname{not} (A \operatorname{and} B)\) (运算操作限制了数位位数为 \(k\))比如 \(2 \operatorname{nand} 3,k=3\),则 \(2 \operatorname{nand} 3=\operatorname{not} (2 \operatorname{and} 3)=\operatorname{not} 2=5\)

给出一棵树,树上每个点都有点权,定义树上从 \(a\)\(b\) 的费用为 \(0\) 与路径上的点的权值顺次 \(\operatorname{nand}\) 的结果,例如:从 \(2\) 号点到 \(5\) 号点顺次经过 \(2\to 3\to 5\),权值分别为 \(5,7,2,k=3\),那么最终结果为 \(0 \operatorname{nand} 5 \operatorname{nand} 7 \operatorname{nand} 2=7 \operatorname{nand} 7 \operatorname{nand} 2=0 \operatorname{nand} 2=7\),现在这棵树需要支持以下操作。

  1. Replace a b:将点 \(a\)\(1\le a\le n\))的权值改为 \(b\)
  2. Query a b:输出点 \(a\) 到点 \(b\) 的费用。

给出一个程序支持这些操作。

Solution

见到位运算,必须考虑拆位。显然运算过程中不同二进制位之间互不影响。对于每一位其实就是 \(0/1\) 之间的变换。
但是这个玩意没有结合律,没有交换律。

可是我们依然可以使用树链剖分,一个路径就会被剖成若干个区间。那么答案就是这堆区间来求出。那么考虑原先答案经过这些区间会有什么影响。树链剖分常常和数据结构一起用。对于每一位,我们可以考虑线段树维护经过一个区间的影响。

\(o\) 表示线段树节点编号,管辖的区间范围为 \([l,r]\),则维护 \(t[o][i][0/1][0/1]\) 表示正着经过(第三维的 \(1\))还是反着经过(第三维的 \(0\)),第 \(i\) 位原本是 \(0/1\) 会变成什么。

这样做的话,pushup 是容易维护的。

树链剖分直接做就好了。

//yinhy 似了关我啥事
//onehow♥liucang forever!
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
#define mx3(a,b,c) ((a>b?a:b)>c?(a>b?a:b):c)
#define mn3(a,b,c) ((a<b?a:b)<c?(a<b?a:b):c)
#define infll 1e16
#define inf 1e9
#define pii pair<int,int>
#define F(i,a,b) for(int i=a;i<=(b);i++)
#define dF(i,a,b) for(int i=a;i>=(b);i--)
#define wh(lzm) while(lzm--)
#define lowbit(x) (x&(-x))
#define HH printf("\n")
#define eb emplace_back
#define vi vector<int>
using namespace std;
int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*f;
}
const int maxn=200005;
int n,lzm,k;
vector<int>g[maxn];
int a[maxn],tim,rev[maxn],d[maxn],dfn[maxn],top[maxn],son[maxn],sz[maxn],fa[maxn];
void dfs(int u,int f){
	d[u]=d[f]+1;
	sz[u]=1;
	fa[u]=f;
	for(int v:g[u]) if(v^f){
		dfs(v,u);
		sz[u]+=sz[v];
		if(sz[v]>sz[son[u]]) son[u]=v;
	}
}
void dfs1(int u,int tt){
	top[u]=tt,dfn[u]=++tim;
	if(!son[u]) return;
	dfs1(son[u],tt);
	for(int v:g[u]) if(v^fa[u]&&v^son[u]) dfs1(v,v);
}
bool fl[maxn];
namespace seg{
	bool t[maxn<<2][33][2][2];
	#define ls (o<<1)
	#define rs (o<<1|1)
	//t[o][i][0/1][0/1] 第i位,正/倒走,0/1会变成什么
    void pushup(int o){
        F(i,0,k){
            t[o][i][0][0]=t[rs][i][0][t[ls][i][0][0]];
            t[o][i][0][1]=t[rs][i][0][t[ls][i][0][1]];
            t[o][i][1][0]=t[ls][i][1][t[rs][i][1][0]];
            t[o][i][1][1]=t[ls][i][1][t[rs][i][1][1]];
        }
	}
	void update(int o,int l,int r,int pos,int x){
		if(l==r){
			F(i,0,k) if(!((1<<i)&x)){
				t[o][i][0][0]=t[o][i][1][0]=1;
				t[o][i][0][1]=t[o][i][1][1]=1;
			}
			else{
				t[o][i][0][0]=t[o][i][1][0]=1;
				t[o][i][0][1]=t[o][i][1][1]=0;
			}
			return;
		}
		int mid=(l+r)>>1;
		if(pos<=mid) update(ls,l,mid,pos,x);
		else update(rs,mid+1,r,pos,x);
		pushup(o);
	}
	void go(int o,int l,int r,int ql,int qr,int op){
		if(qr<ql) return;
		if(ql<=l&&qr>=r){
			if(op) F(i,0,k) fl[i]=t[o][i][1][fl[i]];
			else F(i,0,k) fl[i]=t[o][i][0][fl[i]];
			return;
		}
		int mid=(l+r)>>1;
		if(!op){
			if(ql<=mid) go(ls,l,mid,ql,qr,op);
			if(qr>mid) go(rs,mid+1,r,ql,qr,op);	
			return;
		}
		if(qr>mid) go(rs,mid+1,r,ql,qr,op);
		if(ql<=mid) go(ls,l,mid,ql,qr,op);
	}
}
using namespace seg;
int lca(int u,int v){
	while(top[u]^top[v]){
		if(d[top[u]]<d[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	if(d[u]>d[v]) return v;
	else return u;
}
void goup(int u,int v){
	while(top[u]!=top[v]){
		if(d[top[u]]<d[top[v]]) swap(u,v);
		seg::go(1,1,n,dfn[top[u]],dfn[u],1);
		u=fa[top[u]];
	}
	if(d[u]>d[v]) swap(u,v);
	seg::go(1,1,n,dfn[u],dfn[v],1);
}
vector<pii>tmp;
void godown(int u,int v){
	while(top[u]!=top[v]){
		if(d[top[u]]<d[top[v]]) swap(u,v);
		//dfn[top[u]] dfn[u]
		tmp.eb(dfn[top[u]],dfn[u]);
		u=fa[top[u]];
	}
	if(d[u]>d[v]) swap(u,v);
	tmp.eb(dfn[u]+1,dfn[v]);
}
ll pw[65];
ll solve(int u,int v){
	F(i,0,k) fl[i]=0;
	int t=lca(u,v);
	goup(u,t);
	tmp.clear();
	godown(t,v);
	reverse(tmp.begin(),tmp.end());
	for(auto [l,r]:tmp) seg::go(1,1,n,l,r,0);
	ll ans=0;
	F(i,0,k) if(fl[i]) ans+=pw[i];
	return ans;
}
void change(int x,int y){
	seg::update(1,1,n,dfn[x],y);
}
signed main(){
	pw[0]=1;
	F(i,1,60) pw[i]=pw[i-1]*2ll;
	n=read(),lzm=read(),k=read()-1;
	F(i,1,n) a[i]=read();
	F(i,1,n-1){
		int u=read(),v=read();
		g[u].pb(v),g[v].pb(u);
	}
	dfs(1,0);
	dfs1(1,1);
	F(i,1,n) seg::update(1,1,n,dfn[i],a[i]);
	wh(lzm){
		string op;
		cin>>op;
		int x=read(),y=read();
		if(op=="Query") printf("%lld\n",solve(x,y));
		else change(x,y);
	}
}
posted @   nullptr_qwq  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示