对于$i\in [1,n)$,记$x_{i}$表示经过$(i,r_{i})$的次数,根据出入度平衡,不难得到
$$
2x_{i}-[s_{i}=R]+[i=k]=\sum_{r_{j}=i}x_{j}+\sum_{b_{j}=i}(x_{j}-[s_{j}=R])+[i=1]
$$
根据这$n-1$个方程解得$\{x_{i}\}$,最终答案即$\sum_{i=1}^{n-1}(2x_{i}-[s_{i}=R])$
注意到$k$和$s$仅影响常数项,记系数矩阵为$A$,每次即给定$b$并求$Ax=c$
另外,$A$的行列式即以$n$为根的外向树个数(矩阵树定理),进而$A$满秩
预处理出$A$的逆矩阵$A^{-1}$,即得到$x=A^{-1}c$,单次询问复杂度降为$o(n^{2})$
得到$\{x_{i}\}$后,需要判定合法性,有以下结论——
结论:$\{x_{i}\}$合法当且仅当满足以下两个条件
- $x_{i}$均为非负整数,不存在$x_{i}=0$且$s_{i}=R$
- 对于$x_{i}>0$,存在$i$通过边集$\{(i,r_{i})\mid s_{i}=R\}\cup \{(i,b_{i})\mid s_{i}=B\}$到$k$的路径
关于必要性,第一条显然成立,第二条对这些点按最后一次经过的时间从大到小归纳即可
关于充分性,注意到$\{x_{i}\}$已经确定每条边被经过的次数,且对应的条件保证这些次数合法
在此基础上,对答案从小到大归纳,仅需在图中撤销一条边并保证第二条仍成立即可
若$k$当前出边的点$x_{i}=0$,显然$k$至多被到达一次,并将该边撤销即可
若$k$当前出边的点$x_{i}\ne 0$,找到其到$k$路径上对应的儿子撤销,显然仍成立
关于非负整数的判定,可以对两个$>\max x_{i}$的大素数取模,若结果相同即可看作非负整数
不难证明$\max x_{i}\le 2^{n-2}$,具体的大素数可以参考代码
时间复杂度为$o(n^{3}+qn^{2})$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 60 4 #define ll long long 5 #define LL __int128 6 int n,q,k,r[N],b[N],vis[N]; 7 char s[N];ll ans;vector<int>e[N]; 8 struct Data{ 9 ll mod,a[N][N],ai[N][N],c[N],x[N]; 10 ll mul(ll x,ll y){ 11 return (LL)x*y%mod; 12 } 13 ll qpow(ll n,ll m){ 14 ll s=n,ans=1; 15 while (m){ 16 if (m&1)ans=mul(ans,s); 17 s=mul(s,s),m>>=1; 18 } 19 return ans; 20 } 21 void guess(){ 22 for(int i=1;i<n;i++){ 23 int pos=0; 24 for(int j=i;j<n;j++) 25 if (a[j][i]){pos=j;break;} 26 if (pos!=i){ 27 for(int j=i;j<n;j++)swap(a[i][j],a[pos][j]); 28 for(int j=1;j<n;j++)swap(ai[i][j],ai[pos][j]); 29 } 30 ll s=qpow(a[i][i],mod-2); 31 for(int j=i;j<n;j++)a[i][j]=mul(a[i][j],s); 32 for(int j=1;j<n;j++)ai[i][j]=mul(ai[i][j],s); 33 for(int j=i+1;j<n;j++){ 34 ll s=a[j][i]; 35 for(int k=i;k<n;k++)a[j][k]=(a[j][k]-mul(a[i][k],s)+mod)%mod; 36 for(int k=1;k<n;k++)ai[j][k]=(ai[j][k]-mul(ai[i][k],s)+mod)%mod; 37 } 38 } 39 for(int i=n;i;i--) 40 for(int j=1;j<i;j++){ 41 ll s=a[j][i]; 42 for(int k=1;k<n;k++)ai[j][k]=(ai[j][k]-mul(ai[i][k],s)+mod)%mod; 43 } 44 } 45 void build(ll Mod){ 46 mod=Mod; 47 for(int i=1;i<n;i++){ 48 a[i][i]=2,ai[i][i]=1; 49 for(int j=1;j<n;j++){ 50 a[i][j]-=(r[j]==i)+(b[j]==i); 51 if (a[i][j]<0)a[i][j]+=mod; 52 } 53 } 54 guess(); 55 } 56 void calc(){ 57 for(int i=1;i<n;i++){ 58 c[i]=(i==1)+(s[i]=='R')-(i==k); 59 for(int j=1;j<n;j++) 60 if (b[j]==i)c[i]-=(s[j]=='R'); 61 if (c[i]<0)c[i]+=mod; 62 } 63 for(int i=1;i<n;i++){ 64 x[i]=0; 65 for(int j=1;j<n;j++)x[i]=(x[i]+mul(ai[i][j],c[j]))%mod; 66 } 67 } 68 }A,B; 69 void dfs(int k){ 70 if (vis[k])return; 71 vis[k]=1; 72 for(int i:e[k])dfs(i); 73 } 74 bool check(){ 75 for(int i=1;i<n;i++) 76 if ((A.x[i]!=B.x[i])||(!A.x[i])&&(s[i]=='R'))return 0; 77 memset(vis,0,sizeof(vis)); 78 for(int i=1;i<=n;i++)e[i].clear(); 79 for(int i=1;i<n;i++)e[(s[i]=='R') ? r[i] : b[i]].push_back(i); 80 dfs(k); 81 for(int i=1;i<n;i++) 82 if ((A.x[i])&&(!vis[i]))return 0; 83 return 1; 84 } 85 int main(){ 86 scanf("%d",&n); 87 for(int i=1;i<n;i++)scanf("%d%d",&b[i],&r[i]); 88 A.build(72057594037928017LL); 89 B.build(72057594037928033LL); 90 scanf("%d",&q); 91 for(int i=1;i<=q;i++){ 92 scanf("%d%s",&k,s+1); 93 A.calc(),B.calc(); 94 if (!check())ans=-1; 95 else{ 96 ans=0; 97 for(int j=1;j<n;j++)ans+=(A.x[j]<<1)-(s[j]=='R'); 98 } 99 printf("%lld\n",ans); 100 } 101 return 0; 102 }