题目大意
给定一棵树,每个点有一个权值。
每个点可以选或不选,但最后必须保证每一条边连着的两个点其中一个必选。
如果一个点选,那么就要付出该点权值的代价。
每一个询问,限制两个点必选还是必不选。然后输出最小代价和。
询问之间互相独立。
解题思路
当时在想的时候,已经想到了只限制一个点的做法,然后以为AC了,很开心。
可是由于失误,想到的分没有全都打。
朴素的dp可以拿44分。
对于数据类型2,直接按照只限制一个点的做法即可。
对于链,用线段树维护f,然后分类讨论一下即可。
对于B,直接暴力搞。
考虑到x的选取会对fa[x]有影响,所以:
设 g [ x ] [ 0 / 1 ] g[x][0/1] g[x][0/1]表示x不选/选,fa[x]的子树去掉x的子树的答案。
设 ( h [ x ] [ 0 ] − f [ x ] [ 0 ] ) / ( h [ x ] [ 1 ] − f [ x ] [ 1 ] ) (h[x][0]-f[x][0])/(h[x][1]-f[x][1]) (h[x][0]−f[x][0])/(h[x][1]−f[x][1])表示x不选/选,整棵树去掉x的子树的答案。
计算h的时候通过换根操作求出即可。
设 G [ i ] [ x ] [ 0 / 1 ] [ 0 / 1 ] G[i][x][0/1][0/1] G[i][x][0/1][0/1]表示,去掉x的子树后,x到x的 2 i 2^i 2i祖先的链的g值和。其中x的 2 i 2^i 2i祖先不选/选,x不选/选。
另一种设法: G [ i ] [ x ] [ 0 / 1 ] [ 0 / 1 ] G[i][x][0/1][0/1] G[i][x][0/1][0/1]表示,去掉x的子树后,x到x的 2 i 2^i 2i祖先的链的g值和。其中x的 2 i − 1 2^i-1 2i−1祖先不选/选,x不选/选。
这样的设法,导致合并信息的时候要讨论太多东西。
对于每个询问,考虑倍增。
a为a,b深度较大的那个。
令c=lca(a,b)
对于b=c,那么直接处理好a-b这条链,b两部分的信息。
只需要处理好a-c这条链,c,c-b这条链,b五部分的信息。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 100010
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
#define LL long long
#define Inf 100000000000
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{
int to,next;
}edge[N<<1];
int head[N<<1],tot;
int i,j,k,l,n,m,cs;
LL ans,a0,a1;
int u,v,u2,v2,w;
int X,Y,W;
int a[N];
LL f[N][