这题考场上拿到了50分暴力分海星
首先考虑暴力怎么搞,设dis[i]表示切断i节点与叶子的联系的最优价值
tot[i]表示i节点的所有儿子的dis之和,对于叶子结点,他的tot值为0,dis为val,很容易的得到转移方程dis[i]=min(val[i],tot[i]),
每次更新只会影响到它的父亲以及父亲往上的一条链,直到根节点,所以就可以O(hm)的解决这道题
这是50分做法
那50->100是质的飞越,那是DDP,当然也可以二分,但是我不会
改变一下原先的定义,tot[i]为切断i节点与他所有轻儿子的联系
那么转移方程改变为dis[i]=min(val[i],tot[i]+dis[son[i]])
重儿子展开就是dis[i]=min(val[i],tot[i]+min(val[son[i]],dis[son[son[i]]]+tot[son[i]]))
在一条重链上,一个节点的改变会影响链头的fa的tot值和所有的dis值,
对于tot值单独在外面开一个数组维护,每次需要更新,而dis值在线段树上维护,
如何在线段树上维护?
对于这个东西把它转化成矩阵乘,重新定义一下矩阵乘
乘为加,加为取min,
构造的矩阵为2*2的,左上是0,右上是dis[i],左下是inf,右下是tot[i]。
乘的时候是从右往左乘。
更新的时候需要将链头的fa的tot值中链头原先的dis值,然后更新之后加上新的dis值
对于每次询问都需要访问从链底到当前位置。
这题有点卡常,需要用快读。
代码如下
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define LL long long #define mid ((l+r)>>1) #define lson k<<1,l,mid #define rson k<<1|1,mid+1,r #define ls k<<1 #define rs k<<1|1 #define t(rt,a,b) tr[rt].f[a][b] using namespace std; const int N=200005; const LL inf=1e18; int n,m,cnt,head[N],fa[N],tot; int in[N],dep[N],top[N],dfn[N],id[N],siz[N],son[N],bot[N]; LL vl[N],f[N],g[N]; vector<int>q; struct node{ int to,nxt; }e[N<<1]; struct martix{ LL f[2][2]; martix(){ f[0][0]=f[0][1]=f[1][0]=f[1][1]=0; } inline void init(){ f[0][1]=f[1][0]=inf; } inline void mx(){ f[0][0]=f[0][1]=f[1][0]=f[1][1]=inf; } }; martix tr[N<<2]; martix operator *(const martix &a,const martix &b){ martix res; res.mx(); for(int k=0;k<2;++k) for(int i=0;i<2;i++) for(int j=0;j<2;j++) res.f[i][j]=min(res.f[i][j],a.f[i][k]+b.f[k][j]); return res; } inline int read(){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();} return s*w; } inline void add(int from,int to){ e[++cnt]=(node){to,head[from]}; head[from]=cnt;in[to]++; } void dfs1(int x,int f,int deep){ fa[x]=f;siz[x]=1;dep[x]=deep; int maxson=-1; for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=f){ dfs1(e[i].to,x,deep+1); siz[x]+=siz[e[i].to]; if(siz[e[i].to]>maxson){ son[x]=e[i].to; maxson=siz[e[i].to]; } } } void dfs2(int x,int topf){ f[x]=vl[x];dfn[x]=++tot;id[tot]=x;top[x]=topf; if(son[x]){ dfs2(son[x],topf); bot[x]=bot[son[x]]; } else bot[x]=x; for(int i=head[x];i;i=e[i].nxt){ if(e[i].to==son[x]||e[i].to==fa[x]) continue; dfs2(e[i].to,e[i].to); g[x]+=f[e[i].to]; } if(in[x])f[x]=min(f[x],f[son[x]]+g[x]); } inline void update(int k){ tr[k]=tr[rs]*tr[ls]; } void build(int k,int l,int r){ if(l==r){ t(k,1,0)=inf; t(k,0,1)=vl[id[l]]; t(k,1,1)=g[id[l]]; return ; } build(rson);build(lson); update(k); } martix ask(int k,int l,int r,int x,int y){ if(x<=l&&r<=y){ return tr[k]; } martix res; res.init(); if(y>mid)res=res*ask(rson,x,y); if(x<=mid)res=res*ask(lson,x,y); return res; } inline void mark_f(int x){ while(top[x]!=1){ martix res=ask(1,1,n,dfn[top[x]],dfn[bot[x]]); q.push_back(res.f[0][1]); x=fa[top[x]]; } } void change(int k,int l,int r,int x){ if(l==r&&l==x){ t(k,0,1)=vl[id[x]]; t(k,1,1)=g[id[x]]; return ; } if(x<=mid)change(lson,x); else change(rson,x); update(k); } inline void chenge(int x){ q.clear(); mark_f(x); int tmp=0; while(top[x]!=1){ g[fa[top[x]]]-=q[tmp++]; change(1,1,n,dfn[x]); g[fa[top[x]]]+=ask(1,1,n,dfn[top[x]],dfn[bot[x]]).f[0][1]; x=fa[top[x]]; } change(1,1,n,dfn[x]); } int main(){ n=read(); for(int i=1;i<=n;++i) vl[i]=read(),in[i]=-1; in[1]++; int x,y; for(int i=1;i<n;++i){ x=read();y=read(); add(x,y);add(y,x); } dfs1(1,0,1); dfs2(1,1); build(1,1,n); m=read(); char c[3]; while(m--){ scanf("%s%d",c+1,&x); if(c[1]=='Q') printf("%lld ",ask(1,1,n,dfn[x],dfn[bot[x]]).f[0][1]); else{ y=read(); vl[x]+=y; chenge(x); } } return 0; }