为了方便,对题意做以下处理:
1.称"西部主题"和"科幻主题"分别为黑色和白色
2.删去题中"保证没有两条不同的道路连接同一对景点"的条件
关于题中的条件,即保证图中总存在重边、一度点或二度点(或仅剩一个点)
(具体证明参考2019年的论文,这里就省略了)
考虑对这些特殊的结构进行处理,具体如下——
对于节点$x$,将其点权$w_{x}$用一个$2 imes 1$的矩阵描述,分别为$x$染黑色和白色的美观度
对于边$(x,y)$,将其边权$v_{(x,y)}$用一个$4 imes 1$的矩阵描述,分别为$x$染黑色$y$染黑色、$x$染黑色$y$染白色、$x$染白色$y$染黑色和$x$染白色$y$染白色时这条边的美观度
关于重边,假设两边分别为$e_{1}$和$e_{2}$,构造边权之间的二元运算$oplus$,使得合并后新边边权为$v_{e_{1}}oplus v_{e_{2}}$
关于一度点,假设该点为$x$、出边为$e$、出边终点为$y$,构造点权、边权和点权之间的三元运算$odot$(结果为点权),使得合并后新点点权为$odotleft(w_{x},v_{e},w_{y} ight)$
关于二度点,假设该点为$x$,出边分别为$e_{1}$和$e_{2}$,构造边权、点权和边权之间的三元运算$otimes$(结果为边权),使得合并后新边边权为$otimes(v_{e_{1}},w_{x},v_{e_{2}})$(方向为从$e_{1}$终点指向$e_{2}$终点)
另外,注意到每一条边仅存储了一个方向,可能会导致无法合并,因此还需要一个反向操作
为了让其更形式化,构造边权的一元运算$R$,使得$R(w_{e})$为将$e$反向后的边边权
(为了让阅读更连贯,具体的构造都放在文末)
由此,可以得到一棵表达式树,树上的叶子节点存储初始的点权和边权,非叶子节点存储一种运算(上述四种之一),运算后根节点必然是点权且将两值取$max$即为答案
类似于动态dp,将其树链剖分,问题即是要修改某个位置的值后能快速维护其重链顶端的值
提取一个类似于矩阵乘法的运算$*$,满足$A*B=C$,其中$A,B$和$C$分别是$a imes b,b imes c$和$a imes c$的矩阵,并且有$C_{i,j}=max_{k=1}^{b}(a_{i,k}+b_{k,j})$,显然其与矩阵乘法一样满足结合律
通过这个运算,那么在这之前的四种运算中,每次运算结果都可以看作其中任意一个参与运算的变量左$*$一个矩阵(这个矩阵由剩下的参与运算的变量确定)
由此,在每个位置上记录需要左$*$的矩阵,根据$*$的结合律即可用线段树维护(注意每次要从链尾算起)
总复杂度为$o(nlog^{2}n)$,可以通过

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define M 1000005 5 #define ll long long 6 #define L (k<<1) 7 #define R (L+1) 8 #define mid (l+r>>1) 9 int n,m,V,q,x,y,num[20],op[M],v[M][3]; 10 struct matrix{ 11 int n,m; 12 ll a[4][4]; 13 bool operator != (const matrix &k)const{ 14 if ((n!=k.n)||(m!=k.m))return 1; 15 for(int i=0;i<k.n;i++) 16 for(int j=0;j<m;j++) 17 if (a[i][j]!=k.a[i][j])return 1; 18 return 0; 19 } 20 matrix(){ 21 n=m=0; 22 memset(a,-0x3f,sizeof(a)); 23 } 24 }w[M],trans[M]; 25 int read(){ 26 int x=0; 27 char c=getchar(); 28 while ((c<'0')||(c>'9'))c=getchar(); 29 while ((c>='0')&&(c<='9')){ 30 x=x*10+c-'0'; 31 c=getchar(); 32 } 33 return x; 34 } 35 void write(ll n,char c='