题解:P11992 [JOIST 2025] 电路 2 / Circuit 2
P11992 [JOIST 2025] 电路 2 / Circuit 2
可能没有黑啊,感觉不太难。
先考虑没有次数限制,胡一个简单的做法。
我们尝试从上往下确定符号。考虑怎么区分一个节点是
上面操作涉及到一个问题:怎么做到在传入固定的值。这是简单的,将子树内所有输入全部改为
这样就做到了线性。确认好的点构成了一个包含根的连通块,每次加入一个儿子,可以确定这个儿子的编号。
考虑能不能更高效一点。我们每次取若干个点,判断其中有没有
尝试一点简单的结构:取若干条链,并且这些链的链头的祖先链与其他链都不相交。这样的话,对于每条链,我们尝试在链头给出返回值。具体做法如下:在链尾输入
剩下的任务就是通过一些确定的符号将这些点的信息合并传到根部。考虑树形 DP 求转移方法,
于是我们实现了询问。考虑具体该问哪些点,尝试这样做:每次在一个点集里二分第一个
上面询问次数的分析如下:
上面那个式子在
代码:
#include<bits/stdc++.h>
using namespace std;
std::string solve(int NN, int RR, std::vector<int> U, std::vector<int> V);
int query(std::string s);
int n,R,ans[20003],fa[20003],k1,k2,k3,k4,k5,k6,k7,k8,k9,mxdep[20003],qrymk[20003],rev[20003],lft,rgt,mid;
int stk[20003],tots,dp[20003][2],dep[20003];
vector<int>son[20003];
void dfs(int now){
mxdep[now]=now;
for(auto i:son[now]){
if(i>=n)continue;
dfs(i);
if(dep[mxdep[i]]>dep[mxdep[now]])mxdep[now]=mxdep[i];
if(ans[now]!=-1&&ans[i]==-1){
int u=tots;
for(int j=mxdep[i];;j=fa[j]){
stk[++tots]=j;
if(j==i)break;
}
reverse(stk+u+1,stk+tots+1);
}
}
if(ans[now]==-1&&now==0){
int u=tots;
for(int j=mxdep[now];;j=fa[j]){
stk[++tots]=j;
if(j==now)break;
}
reverse(stk+u+1,stk+tots+1);
}
return;
}
void mdf(int pos){
dp[pos][0]^=1;dp[pos][1]^=1;rev[pos]^=1;
return;
}
void dfs2(int now){
if(now>=n){
dp[now][0]=dp[now][1]=0;
return;
}
int u=son[now][0],v=son[now][1];
dfs2(u);dfs2(v);
if(qrymk[now]){
if(dp[v][0]==dp[v][1])swap(u,v);
if(dp[u][0]==0)mdf(u);
if(dp[v][0]==1)mdf(v);
dp[now][0]=0;
dp[now][1]=1;
}
else{
if(dp[v][0]==dp[v][1])swap(u,v);
if(dp[u][0]==dp[u][1]&&dp[v][0]==dp[v][1]){
if(dp[u][0]==0)mdf(u);
if(dp[v][0]==0)mdf(v);
dp[now][0]=dp[now][1]=1;
return;
}
if(dp[u][0]==dp[u][1]){
if(ans[now]==0){if(dp[u][0]==0)mdf(u);}
else if(dp[u][0]==1)mdf(u);
dp[now][0]=dp[v][0];dp[now][1]=dp[v][1];
}
else{
if(ans[now]==0){
if(dp[u][0]==0)mdf(u);
if(dp[v][0]==0)mdf(v);
dp[now][0]=1;dp[now][1]=0;
}
else{
if(dp[u][0]==1)mdf(u);
if(dp[v][0]==1)mdf(v);
dp[now][0]=0;dp[now][1]=1;
}
}
}
return;
}
int Query(int pos){
for(int i=0;i<=n*2;i++)rev[i]=qrymk[i]=0;
for(int i=1;i<=pos;i++)qrymk[stk[i]]=1;
dfs2(0);
string qs="";
for(int i=0;i<=n*2;i++)qs+=(char)('0'+rev[i]);
return (query(qs)==dp[0][1]);
}
string solve(int NN,int RR,vector<int> U,vector<int> V) {
n=NN;R=RR;
dep[0]=1;
for(int i=0;i<n;i++){
son[i].emplace_back(U[i]);
son[i].emplace_back(V[i]);
dep[U[i]]=dep[V[i]]=dep[i]+1;
fa[U[i]]=fa[V[i]]=i;
}
for(int i=0;i<n;i++)ans[i]=-1;
while(1){
k1=1;
for(int i=0;i<n;i++)if(ans[i]==-1)k1=0;
if(k1)break;
tots=0;
dfs(0);
tots=min(tots,60);
if(!Query(tots)){
for(int i=1;i<=tots;i++)ans[stk[i]]=0;
continue;
}
lft=1;rgt=tots;
while(lft<rgt){
mid=((lft+rgt)/2);
if(Query(mid))rgt=mid;
else lft=mid+1;
}
for(int i=1;i<lft;i++)ans[stk[i]]=0;
ans[stk[lft]]=1;
}
string ret="";
for(int i=0;i<n;i++){
if(ans[i])ret+='|';
else ret+='&';
}
return ret;
}