• [cf1266H]RedBlue 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
  • 相关阅读:
    SSRS_NOTE
    github快速使用指南
    Serving 404s instead of errors solved :)
    如何提高LINQtoSQL延时加载的性能
    SqlServer开发利器—SQL Prompt5
    内核通知链 学习笔记 arm
    Excel报表之js版
    JS修改Table中Td的值。
    什么时候能忙完~
    JS修改Table中Td的值(修改)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16362768.html
Copyright © 2020-2023  润新知