• bzoj2286 消耗战


    还是虚树的题目啊...

    如果只有一个询问,我们这么考虑,可以设dp[x]为只删除x子树内和x到父亲的边,使得x这棵子树内的能源岛屿都与x的父亲不连通的最小花费。

    这样如果x本身是能源岛屿,那么dp[x]=fe[x],否则dp[x]=min(fe[x],sum{dp[son[x]]})类似这样。(fe表示父亲边,fe[1]=inf)

    那么有了多组询问我们就在虚树上搞这个,需要注意的是虚树上的一条父子边就对应着原树上一条父子链,而权值就是那个父子链的最小值。可以用倍增一起维护掉。

    需要注意的是...要用long long啊

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <algorithm>
    #include <string.h>
    #include <math.h>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    int inf=1000000000;
    ll inf_ll=10000000000000000LL;
    #define gc getchar()
    int g_i()
    {
        int tmp=0; bool fu=0; char s;
        while(s=gc,s!='-'&&(s<'0'||s>'9')) ;
        if(s=='-') fu=1; else tmp=s-'0';
        while(s=gc,s>='0'&&s<='9') tmp=tmp*10+s-'0';
        if(fu) return -tmp; else return tmp;
    }
    #define gi g_i()
    #define pob
    #define pc(x) putchar(x)
    namespace ib {char b[100];}
    inline void pll(ll x)
    {
        if(x==0) {pc(48); return;}
        if(x<0) {pc('-'); x=-x;}
        char *s=ib::b;
        while(x) *(++s)=x%10, x/=10;
        while(s!=ib::b) pc((*(s--))+48);
    }
    #define SZ 1234567
    #define D 20
    #define _els ;else
    //real tree
    namespace rt
    {
    int n,fst[SZ],nxt[SZ],vb[SZ],vc[SZ],fa[SZ],dep[SZ],M=0,dfsn[SZ],C=0,sz[SZ],fe[SZ];
    int up[SZ][D],mine[SZ][D];
    void ad_de(int a,int b,int c) {++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; vc[M]=c;}
    void adde(int a,int b,int c) {ad_de(a,b,c); ad_de(b,a,c);}
    void dfs(int p)
    {
        dfsn[p]=++C; sz[p]=1;
        for(int e=fst[p];e;e=nxt[e])
        {
            int b=vb[e]; if(b==fa[p]) continue;
            fa[b]=up[b][0]=p; fe[b]=vc[e]; mine[b][0]=fe[b];
            dep[b]=dep[p]+1; dfs(b); sz[p]+=sz[b];
        }
    }
    void build()
    {
        dfs(1);
        for(int g=1;g<D;g++)
        {
            for(int i=1;i<=n;i++) mine[i][g]=inf;
        }
        for(int g=1;g<D;g++)
        {
            for(int i=1;i<=n;i++)
            {
                if(!up[i][g-1]) continue;
                up[i][g]=up[up[i][g-1]][g-1];
                mine[i][g]=min(mine[i][g-1],mine[up[i][g-1]][g-1]);
            }
        }
    }
    //jump up (x=fa[x]) until dep[x]=d
    int jmp(int x,int d)
    {
        for(int i=D-1;i>=0;i--)
        {
            if(!up[x][i]||dep[up[x][i]]<d)_els x=up[x][i];
        }
        return x;
    }
    int gmin(int x,int d)
    {
        int minn=inf;
        for(int i=D-1;i>=0;i--)
        {
            if(!up[x][i]||dep[up[x][i]]<d)_els minn=min(minn,mine[x][i]), x=up[x][i];
        }
        return minn;
    }
    int lca(int x,int y)
    {
        if(dep[x]>dep[y]) swap(x,y);
        y=jmp(y,dep[x]);
        if(x==y) return x;
        for(int i=D-1;i>=0;i--)
        {
            if(up[x][i]!=up[y][i]) x=up[x][i], y=up[y][i];
        }
        return fa[x];
    }
    }
    //virtual tree
    namespace vt
    {
    #define f_ first
    #define s_ second
    typedef pair<int,int> pii;
    //vs: points in vtree 
    int sn,ss[SZ],vn,vs[SZ],stn=0,st[SZ],vfa[SZ],fc[SZ],nc[SZ];
    ll f[SZ],vfe[SZ];
    bool saf[SZ];
    bool cmp_dfsn(int a,int b) {return rt::dfsn[a]<rt::dfsn[b];}
    ll dp(int x)
    {
        if(!saf[x]) return f[x]=vfe[x];
        ll sum=0;
        for(int c=fc[x];c;c=nc[c]) sum+=dp(c);
        return f[x]=min((ll)vfe[x],sum);
    }
    void build()
    {
        vn=stn=0;
        ss[++sn]=1;
        sort(ss+1,ss+1+sn,cmp_dfsn);
        for(int i=1;i<=sn;i++) vs[++vn]=ss[i], saf[ss[i]]=i==1;
        for(int i=1;i<=sn;i++)
        {
            int x=ss[i];
            if(!stn) {st[++stn]=x; vfa[x]=0; continue;}
            int lca=rt::lca(x,st[stn]);
            for(;rt::dep[st[stn]]>rt::dep[lca];--stn)
            {
                if(rt::dep[st[stn-1]]<=rt::dep[lca]) vfa[st[stn]]=lca; 
            }
            if(st[stn]!=lca)
            {
                vs[++vn]=lca;
                saf[lca]=1;
                vfa[lca]=st[stn];
                st[++stn]=lca;
            }
            vfa[x]=lca; st[++stn]=x;
        }
        sort(vs+1,vs+1+vn,cmp_dfsn);
        for(int i=1;i<=vn;i++) fc[vs[i]]=0;
        for(int i=1;i<=vn;i++)
        {
            int x=vs[i]; f[x]=inf_ll;
            if(i>1) vfe[x]=rt::gmin(x,rt::dep[vfa[x]]);
            else vfe[x]=inf_ll;
            int f=vfa[x];
            nc[x]=fc[f]; fc[f]=x;
        }
        pll(dp(1)); pc(10);
    }
    }
    int main()
    {
        rt::n=gi;
        for(int i=1;i<rt::n;i++)
        {
            int x=gi,y=gi,z=gi;
            rt::adde(x,y,z);
        }
        rt::build();
        int q=gi;
        while(q--)
        {
            vt::sn=gi;
            for(int i=1;i<=vt::sn;i++) vt::ss[i]=gi;
            vt::build();
        }
    }
  • 相关阅读:
    pcDuino无显示器刷机与使用
    pcDuino安装vnc进行远程控制
    pcDuino 刷系统-卡刷
    HDU 5441 2015长春站online1005(并查集)
    HYSBZ 2002 Bounce 弹飞绵羊(分块)
    HYSBZ 2243 染色 LCT学习
    HYSBZ 2049 Cave 洞穴勘测
    SPOJ 375 LCT学习
    HDU 4010 动态树LCT学习
    ZJOI2008 树的统计 树链剖分学习
  • 原文地址:https://www.cnblogs.com/zzqsblog/p/5568636.html
Copyright © 2020-2023  润新知