[bzoj5466] [loj#2955] [NOIP2018] 保卫王国
作者:互联网
题意简述
\(n\) 个点的树,每个点有点权。
要求选若干个点,满足任意两个有边相连的点中至少选一个,要选的所有点点权和最小。
\(m\) 个询问,每个询问强制规定两个点是否选,求最小点权和。
\(n,m \leq 10^5\)
想法
动态 \(DP\) ,算是比较模板的题了……
模板戳这里
朴素的方程为
\[
f[u][0]=\sum\limits_{fa[v]=u} f[v][1] \\
f[u][1]=val[u]+\sum\limits_{fa[v]=u} min(f[v][0],f[v][0])
\]
令 \(g[u][0/1]\) 为只考虑轻子的 \(dp\) 值。
设 \(v\) 为重子,则有
\[
\begin{equation*}
\left(
\begin{array}{cc}
\infty& g[u][0] \\
g[u][1]& g[u][1]
\end{array}
\right )
\times
\left(
\begin{array}{cc}
f[v][0]\\
f[v][1]
\end{array}
\right )
=
\left(
\begin{array}{cc}
f[u][0]\\
f[u][1]
\end{array}
\right )
\end{equation*}
\]
问题是那两个被强制选或不选的点怎么搞。
如果一个点强制不选,可理解成 \(val[x]=INF\),即\(g[x][1]=INF\);如果强制选,则 \(g[x][0]=INF\)。
然后就很模板了(虽然仍很难写……)
总结(吐槽)
算法上
一开始两点一块儿考虑的,类似跳 \(lca\) ,又 \(wa\) 又 \(tle\) 又难写……
代码飙到了326行(目前写过最长的【捂脸】),然后0分……
唯一有趣的是,两点一块儿跳让我想到了几天前看的电影,于是——
说起来这个代码和 \(Titanic\) 也挺像的……又长又慢又漏洞百出……
这告诉我,三思而后写代码!!!
其他
\(LOJ\) 上需要加文件读写!文件读写!文件读写!!!!!为此我 \(T\) 了许久。。。浪费生命。。。
这真的是联赛题???太可怕了。。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x;
}
const int N = 200005;
typedef long long ll;
const ll INF = 100000000000;
int n,m,val[N];
struct node{
int v;
node *nxt;
}pool[N*2],*h[N];
int cnt1;
void addedge(int u,int v){
node *p=&pool[++cnt1],*q=&pool[++cnt1];
p->v=v;p->nxt=h[u];h[u]=p;
q->v=u;q->nxt=h[v];h[v]=q;
}
int tot,dfn[N],top[N],re[N],bot[N],sz[N],son[N],dep[N],fa[N];
void dfs1(int u){
int v,Bson=0;
sz[u]=1;
for(node *p=h[u];p;p=p->nxt)
if(!sz[v=p->v]){
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>Bson) Bson=sz[v],son[u]=v;
}
}
void dfs2(int u){
int v=son[u];
if(v){
top[v]=top[u];
dfn[v]=++tot;
re[tot]=v;
dfs2(v);
}
else bot[top[u]]=u;
for(node *p=h[u];p;p=p->nxt)
if(!dfn[v=p->v]){
top[v]=v;
dfn[v]=++tot;
re[tot]=v;
dfs2(v);
}
}
struct Mat{
ll a[2][2];
Mat() { a[0][0]=a[0][1]=a[1][0]=a[1][1]=0; }
Mat operator * (const Mat &b) const{
Mat c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++){
c.a[i][j]=INF;
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;
}
}m0[N],mm[N*2],Pre[N*2];
ll g0,g1;
void getm(int u){
int v;
Mat c;
m0[u].a[0][0]=INF; m0[u].a[0][1]=0; m0[u].a[1][0]=m0[u].a[1][1]=val[u];
for(node *p=h[u];p;p=p->nxt)
if(fa[v=p->v]==u && v!=son[u]){
getm(v);
c.a[0][0]=g0; c.a[1][0]=g1; c.a[0][1]=c.a[1][1]=0;
c=m0[u]*c;
m0[u].a[0][0]=INF; m0[u].a[0][1]=c.a[0][0]; m0[u].a[1][0]=m0[u].a[1][1]=c.a[1][0];
}
if(v=son[u]){
getm(v);
c.a[0][0]=g0; c.a[1][0]=g1; c.a[0][1]=c.a[1][1]=0;
c=m0[u]*c;
g0=c.a[0][0]; g1=c.a[1][0];
}
else g0=0,g1=val[u];
}
int cnt,root,ch[N*2][2],lazy[N*2];
void build(int x,int l,int r){
if(l==r) { mm[x]=m0[re[l]]; Pre[x]=mm[x]; return; }
int mid=(l+r)>>1;
build(ch[x][0]=++cnt,l,mid);
build(ch[x][1]=++cnt,mid+1,r);
mm[x]=mm[ch[x][0]]*mm[ch[x][1]];
Pre[x]=mm[x];
}
Mat sum(int x,int l,int r,int L,int R){
if(l==L && r==R) return mm[x];
int mid=(l+r)>>1;
if(R<=mid) return sum(ch[x][0],l,mid,L,R);
if(L>mid) return sum(ch[x][1],mid+1,r,L,R);
return sum(ch[x][0],l,mid,L,mid)*sum(ch[x][1],mid+1,r,mid+1,R);
}
Mat S(int l,int r) { return sum(root,1,n,l,r); }
void Reset(int x,int l,int r){
if(!lazy[x]) return;
mm[x]=Pre[x]; lazy[x]=0;
if(l==r) return;
int mid=(l+r)>>1;
Reset(ch[x][0],l,mid); Reset(ch[x][1],mid+1,r);
}
void modify(int x,int l,int r,int c,ll y0,ll y1){
lazy[x]=1;
if(l==r) {
mm[x].a[0][1]=min(mm[x].a[0][1]+y0,INF); mm[x].a[0][0]=INF;
mm[x].a[1][0]=min(mm[x].a[1][0]+y1,INF); mm[x].a[1][1]=mm[x].a[1][0];
return;
}
int mid=(l+r)>>1;
if(c<=mid) modify(ch[x][0],l,mid,c,y0,y1);
else modify(ch[x][1],mid+1,r,c,y0,y1);
mm[x]=mm[ch[x][0]]*mm[ch[x][1]];
}
void Jump(int x,int sx){
ll p0,p1,gx0,gx1;
Mat g;
if(sx==0) g0=0,g1=INF;
else g1=0,g0=INF;
while(x){
g=S(dfn[top[x]],dfn[bot[top[x]]]);//p
p0=min(g.a[0][0],g.a[0][1]); p1=min(g.a[1][0],g.a[1][1]);
modify(root,1,n,dfn[x],g0,g1);//change
g=S(dfn[top[x]],dfn[bot[top[x]]]);//g
gx0=min(g.a[0][0],g.a[0][1]); gx1=min(g.a[1][0],g.a[1][1]);
g0=gx1-p1; g1=min(gx0,gx1)-min(p0,p1);/**/
x=fa[top[x]];
}
}
int main()
{
n=read(); m=read();
char ch[5]; scanf("%s",ch);
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<n;i++) addedge(read(),read());
dep[1]=1; dfs1(1);
top[1]=1; dfn[1]=++tot; re[1]=1; dfs2(1);
getm(1);
build(root=++cnt,1,n);
int x,y,sx,sy;
Mat c;
for(int i=0;i<m;i++){
x=read(); sx=read(); y=read(); sy=read();
if((x==fa[y] || y==fa[x]) && sx==0 && sy==0) { printf("-1\n"); continue; }
Jump(x,sx); Jump(y,sy);
c=S(1,dfn[bot[1]]);
printf("%lld\n",min(min(c.a[0][0],c.a[0][1]),min(c.a[1][0],c.a[1][1])));
Reset(root,1,n);
}
return 0;
}
标签:mm,ch,bzoj5466,loj,mid,NOIP2018,int,return,INF 来源: https://www.cnblogs.com/lindalee/p/12336916.html