zoukankan      html  css  js  c++  java
  • [bzoj5466] [loj#2955] [NOIP2018] 保卫王国

    题意简述

    (n) 个点的树,每个点有点权。
    要求选若干个点,满足任意两个有边相连的点中至少选一个,要选的所有点点权和最小。
    (m) 个询问,每个询问强制规定两个点是否选,求最小点权和。
    (n,m leq 10^5)


    想法

    动态 (DP) ,算是比较模板的题了……
    模板戳这里

    朴素的方程为

    [f[u][0]=sumlimits_{fa[v]=u} f[v][1] \ f[u][1]=val[u]+sumlimits_{fa[v]=u} min(f[v][0],f[v][0]) ]

    (g[u][0/1]) 为只考虑轻子的 (dp) 值。
    (v) 为重子,则有

    [egin{equation*} left( egin{array}{cc} infty& g[u][0] \ g[u][1]& g[u][1] end{array} ight ) imes left( egin{array}{cc} f[v][0]\ f[v][1] end{array} ight ) = left( egin{array}{cc} f[u][0]\ f[u][1] end{array} ight ) 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
    "); continue; }
            Jump(x,sx); Jump(y,sy);
            c=S(1,dfn[bot[1]]);
            printf("%lld
    ",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;
    }
    
  • 相关阅读:
    基于emWin的WAV,MP3软解软件播放器,带类似千千静听频谱,含uCOS-III和FreeRTOS两个版本
    [Linux-CentOS7]yum清华源CentOS7
    [Python]random生成随机6位验证码
    [Python]公司接口返回值规范
    [MacOS]Chrome 强制刷新
    Mybatis的XML中数字不为空的判断
    康师傅JVM:执行引擎(十二)
    Qt 随机颜色的生成
    Qt QVector常见使用方法
    Qt 判断文件是否存在
  • 原文地址:https://www.cnblogs.com/lindalee/p/12336916.html
Copyright © 2011-2022 走看看