题目大意: 我去好长啊不写了qwq
题解
NOIp 太恶心了,又出了一道模板题,这告诉了我们多刷板子的重要性。
没错,这是个动态dp的模板。
这题的转移方程为:
{
f
i
,
0
=
∑
f
s
o
n
,
1
f
i
,
1
=
v
a
l
i
+
∑
max
(
f
s
o
n
,
0
,
f
s
o
n
,
1
)
\begin{cases} f_{i,0}=\sum f_{son,1}\\ f_{i,1}=val_i+\sum \max(f_{son,0},f_{son,1}) \end{cases}
{fi,0=∑fson,1fi,1=vali+∑max(fson,0,fson,1)
用树链剖分维护一下,
g
i
,
0
g_{i,0}
gi,0 和
g
i
,
1
g_{i,1}
gi,1 分别表示不选
i
i
i 和选
i
i
i 的非重子树的最优解,那么有(
s
o
n
son
son 表示重儿子):
(
g
i
,
1
+
v
a
l
i
g
i
,
1
+
v
a
l
i
g
i
,
0
i
n
f
)
×
(
f
s
o
n
,
1
f
s
o
n
,
0
)
=
(
f
i
,
1
f
i
,
0
)
\left( \begin{array}{c} g_{i,1}+val_i & g_{i,1}+val_i\\ g_{i,0} & inf \end{array} \right)\times \left( \begin{array}{c} f_{son,1}\\ f_{son,0}\\ \end{array} \right)= \left( \begin{array}{c} f_{i,1}\\ f_{i,0}\\ \end{array} \right)
(gi,1+valigi,0gi,1+valiinf)×(fson,1fson,0)=(fi,1fi,0)
然后维护 g g g 就好了。
(看不懂的话请务必点开上面的连接把板子先学了)
对于每个询问,将这两个点的值改成 i n f inf inf 或 − i n f -inf −inf 即可使得强制选或不选。
代码如下(由于懒得卡常于是吸了口氧qwq):
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
#define maxn 100010
#define ll long long
#define inf 999999999
int n,m;
char type[5];
int val[maxn];
struct edge{int y,next;};
edge e[2*maxn];
int first[maxn];
void buildroad(int x,int y)
{
static int len=0;
e[++len]=(edge){y,first[x]};
first[x]=len;
}
map<int,map<int,bool> >mmp;
int fa[maxn],size[maxn],mson[maxn];
void dfs1(int x)
{
size[x]=1;
for(int i=first[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa[x])continue;
fa[y]=x;
dfs1(y);
size[x]+=size[y];
if(size[y]>size[mson[x]])mson[x]=y;
}
}
int now[maxn],old[maxn],id=0,top[maxn];
int be[maxn],bottom[maxn],cnt=0;
void dfs2(int x,int tp,int belong)
{
now[x]=++id;old[id]=x;top[x]=tp;be[x]=belong;
if(mson[x]==0){bottom[belong]=x;return;}
dfs2(mson[x],tp,belong);
for(int i=first[x];i;i=e[i].next)
if(e[i].y!=fa[x]&&e[i].y!=mson[x])dfs2(e[i].y,e[i].y,++cnt);
}
ll g[maxn][2][2],f[maxn][2];
/*
g[i][1] , g[i][1]
g[i][0] , inf
*/
void dp(int x)
{
g[x][0][0]=val[x];g[x][1][1]=inf;
f[x][1]=val[x];
for(int i=first[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa[x])continue;
dp(y);
f[x][0]+=f[y][1];
f[x][1]+=min(f[y][0],f[y][1]);
if(y!=mson[x])
{
g[x][0][0]+=min(f[y][0],f[y][1]);
g[x][1][0]+=f[y][1];
}
}
g[x][0][1]=g[x][0][0];
}
struct matrix{
ll a[2][2];
matrix(){memset(a,63,sizeof(a));}
void set(ll s[2][2])
{
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
a[i][j]=s[i][j];
}
matrix operator *(const matrix b)
{
matrix c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
c.a[i][j]=min(c.a[i][j],a[i][k]+b.a[k][j]);
return c;
}
};
struct node{
int l,r;
matrix z;
node *zuo,*you;
node(int x,int y)
{
l=x,r=y;
if(l<r)
{
int mid=l+r>>1;
zuo=new node(l,mid);
you=new node(mid+1,r);
z=zuo->z*you->z;
}
else zuo=you=NULL,z.set(g[old[l]]);
}
void change(int x)
{
if(l==r){z.set(g[old[l]]);return;}
int mid=l+r>>1;
if(x<=mid)zuo->change(x);
else you->change(x);
z=zuo->z*you->z;
}
matrix ask(int x,int y)
{
if(l==x&&r==y)return z;
int mid=l+r>>1;
if(y<=mid)return zuo->ask(x,y);
else if(x>=mid+1)return you->ask(x,y);
else return zuo->ask(x,mid)*you->ask(mid+1,y);
}
};
node *root=NULL;
/*
g_{i,1} g_{i,1}
g_{i,0} inf
*/
matrix before,after;
void change(int x,int y)
{
g[x][0][0]+=y;g[x][0][1]=g[x][0][0];
while(x!=0)
{
before=root->ask(now[top[x]],now[bottom[be[x]]]);
root->change(now[x]);
after=root->ask(now[top[x]],now[bottom[be[x]]]);
x=fa[top[x]];
g[x][0][0]+=min(after.a[0][0],after.a[1][0])-min(before.a[0][0],before.a[1][0]);
g[x][0][1]=g[x][0][0];
g[x][1][0]+=after.a[0][0]-before.a[0][0];
}
}
int main()
{
scanf("%d %d %s",&n,&m,&type);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
for(int i=1,x,y;i<n;i++)
scanf("%d %d",&x,&y),buildroad(x,y),buildroad(y,x),mmp[x][y]=mmp[y][x]=true;
dfs1(1);
dfs2(1,1,++cnt);
dp(1);
root=new node(1,n);
for(int i=1,x,xx,y,yy;i<=m;i++)
{
scanf("%d %d %d %d",&x,&xx,&y,&yy);
if(xx==0&&yy==0&&mmp[x][y])
{
printf("-1\n");
continue;
}
ll ans=0;
if(xx==0)change(x,inf-val[x]);
else change(x,-inf-val[x]),ans+=inf+val[x];
if(yy==0)change(y,inf-val[y]);
else change(y,-inf-val[y]),ans+=inf+val[y];
matrix re=root->ask(now[1],now[bottom[be[1]]]);
if(x==1)ans+=re.a[(xx^1)][0];
else if(y==1)ans+=re.a[(yy^1)][0];
else ans+=min(re.a[0][0],re.a[1][0]);
printf("%lld\n",ans);
change(x,val[x]-(xx?-inf:inf));change(y,val[y]-(yy?-inf:inf));
}
}