[cf1266H]Red-Blue Graph

对于$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})$,可以通过

  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 }
View Code

 

posted @ 2022-06-10 12:04  PYWBKTDA  阅读(105)  评论(0编辑  收藏  举报