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\),现在这棵树需要支持以下操作。
Replace a b
:将点 \(a\)(\(1\le a\le n\))的权值改为 \(b\)。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);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本