传送门
题意简述:
m m m次询问,每次规定两个点必须选或者不选,求树上的带权最小覆盖。
思路:
考虑链分治+ d d p ddp ddp
仍然是熟悉的套路,先考虑没有修改的状态和转移:
令 f i , 0 / 1 f_{i,0/1} fi,0/1表示强制 i i i不选/选时 i i i为根子树的带权最小覆盖。
显然有:
f i , 0 = ∑ v ∈ s o n f v , 1 f_{i,0}=\sum_{v\in son}f_{v,1} fi,0=∑v∈sonfv,1
f i , 1 = v a l p + ∑ v ∈ s o n m i n { f v , 0 , f v , 1 } f_{i,1}=val_p+\sum_{v\in son}min\{f_{v,0},f_{v,1}\} fi,1=valp+∑v∈sonmin{fv,0,fv,1}
这两个转移式。
现在分轻重儿子转移因此再定义两个状态:
令 g i , 0 / 1 g_{i,0/1} gi,0/1表示强制 i i i不选/选时 i i i为根子树去掉 i i i重儿子为根子树的带权最小覆盖。
g i , 0 = ∑ v ∈ s o n , v ̸ = h s o n f v , 1 g_{i,0}=\sum_{v\in son,v\not=hson}f_{v,1} gi,0=∑v∈son,v̸=hsonfv,1
g i , 1 = v a l p + ∑ v ∈ s o n , v ̸ = h s o n m i n { f v , 0 , f v , 1 } g_{i,1}=val_p+\sum_{v\in son,v\not=hson}min\{f_{v,0},f_{v,1}\} gi,1=valp+∑v∈son,v̸=hsonmin{fv,0,fv,1}
于是我们将 f f f的转移式进行变换:
f i , 0 = g i , 0 + f h s o n , 1 f_{i,0}=g_{i,0}+f_{hson,1} fi,0=gi,0+fhson,1
f i , 1 = g i , 1 + v a l i + m i n { f h s o n , 0 , f h s o n , 1 } f_{i,1}=g_{i,1}+val_i+min\{f_{hson,0},f_{hson,1}\} fi,1=gi,1+vali+min{fhson,0,fhson,1}
再把这个写成矩阵的形式:
( f i , 0 f i , 1 ) = ( ∞ g i , 0 g i , 1 + v a l i g i , 1 + v a l i ) ( f h s o n , 0 f h s o n , 1 ) \left( \begin{matrix} f_{i,0}\\ f_{i,1}\\ \end{matrix} \right)= \left( \begin{matrix} \infin&g_{i,0}\\ g_{i,1}+val_i&g_{i,1}+val_i\\ \end{matrix} \right) \left( \begin{matrix} f_{hson,0}\\ f_{hson,1}\\ \end{matrix} \right) (fi,0fi,1)=(∞gi,1+valigi,0gi,1+vali)(fhson,0fhson,1)
注意要重定义矩阵运算时的加法和乘法:
乘法 ⇒ \Rightarrow ⇒加法
加法 ⇒ \Rightarrow ⇒取 m i n min min
然后对于每个链开一棵线段树维护即可。
常数巨大 没错bzojRank最后一个就是我常数巨大的树剖写法
代码:
#include
#define ri register int
#define fi first
#define se second
using namespace std;
const int N=1e5+5;
typedef long long ll;
typedef pair<ll,ll> pii;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,fa[N],siz[N],top[N],hson[N],bot[N],num[N],pred[N],tot=0;
ll f[N][2],g[N][2],a[N];
vector<int>e[N];
void dfs1(int p){
siz[p]=1;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fa[p])continue;
fa[v]=p,dfs1(v),siz[p]+=siz[v];
if(siz[v]>siz[hson[p]])hson[p]=v;
}
}
void dfs2(int p,int tp){
top[p]=tp,pred[num[p]=++tot]=p,bot[tp]=p;
f[p][0]=g[p][0]=g[p][1]=0,f[p][1]=a[p];
if(!hson[p])return;
dfs2(hson[p],tp);
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fa[p]||v==hson[p])continue;
dfs2(v,v);
g[p][0]+=f[v][1];
g[p][1]+=min(f[v][0],f[v][1]);
}
f[p][0]=g[p][0]+f[hson[p]][1];
f[p][1]=g[p][1]+a[p]+min(f[hson[p]][0],f[hson[p]][1]);
}
const ll inf=1e15,Inf=1e17;
struct Mat{
ll a[2][2];
inline ll*operator[](const int&k){return a[k];}
inline void clear(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=Inf;}
friend inline Mat operator*(Mat A,Mat B){
Mat ret;
ret.clear();
for(ri i=0;i<2;++i)for(ri k=0;k<2;++k)if(A[i][k]^Inf)
for(ri j=0;j<2;++j)if(B[k][j]^Inf)ret[i][j]=min(ret[i][j],A[i][k]+B[k][j]);
return ret;
}
};
namespace SGT{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
struct Node{
Mat trans;
int l,r;
ll g[2],v,f[2];
inline void init(){
trans[0][0]=Inf,trans[0][1]=g[0];
trans[1][0]=g[1]+v,trans[1][1]=g[1]+v;
}
inline pii val(){return pii(f[0],f[1]);}
}T[N<<2];
inline void Set(int p){
int k=pred[T[p].l];
T[p].g[0]=g[k][0],T[p].g[1]=g[k][1],T[p].v=a[k];
T[p].f[0]=f[k][0],T[p].f[1]=f[k][1];
T[p].init();
}
inline void pushup(int p){T[p].trans=T[lc].trans*T[rc].trans;}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r;
if(l==r)return Set(p);
build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int k){
if(T[p].l==T[p].r)return Set(p);
update(k<=mid?lc:rc,k),pushup(p);
}
inline Mat query(int p,int ql,int qr){
if(ql<=T[p].l&&T[p].r<=qr)return T[p].trans;
if(qr<=mid)return query(lc,ql,qr);
if(ql>mid)return query(rc,ql,qr);
return query(lc,ql,qr)*query(rc,ql,qr);
}
inline pii query(int p,int k){
if(T[p].l==T[p].r)return T[p].val();
return query(k<=mid?lc:rc,k);
}
}
inline pii ask(int p){
int bt=bot[top[p]];
pii ret=SGT::query(1,num[bt]);
if(bt==p)return ret;
Mat upd=SGT::query(1,num[p],num[bt]-1);
return pii(min(ret.fi+upd[0][0],ret.se+upd[0][1]),min(ret.fi+upd[1][0],ret.se+upd[1][1]));
}
inline void update(int p,ll x){
f[p][1]+=x-a[p],a[p]=x;
while(p){
int ft=fa[top[p]],tp=top[p];
if(ft){
pii tmp=ask(tp);
g[ft][0]-=tmp.se;
g[ft][1]-=min(tmp.fi,tmp.se);
}
SGT::update(1,num[p]);
if(ft){
pii tmp=ask(tp);
g[ft][0]+=tmp.se;
g[ft][1]+=min(tmp.fi,tmp.se);
f[ft][0]=g[ft][0]+f[hson[ft]][1];
f[ft][1]=g[ft][1]+a[p]+min(f[hson[ft]][0],f[hson[ft]][1]);
}
p=ft;
}
}
char s[5];
int main(){
n=read(),m=read();
scanf("%s",s);
for(ri i=1;i<=n;++i)a[i]=read();
for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
dfs1(1),dfs2(1,1),SGT::build(1,1,n);
for(ri x,y,t1,t2,vx,vy;m;--m){
x=read(),t1=read(),y=read(),t2=read();
if(!t1&&!t2&&(fa[x]==y||fa[y]==x)){puts("-1");continue;}
vx=a[x],vy=a[y];
update(x,t1?a[x]-inf:a[x]+inf),update(y,t2?a[y]-inf:a[y]+inf);
pii tmp=ask(1);
ll ans=min(tmp.fi,tmp.se);
if(t1)ans+=inf;
if(t2)ans+=inf;
cout<<ans<<'\n';
update(x,vx),update(y,vy);
}
return 0;
}