[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;
}

猜你喜欢

转载自www.cnblogs.com/lindalee/p/12336916.html
今日推荐