zoukankan      html  css  js  c++  java
  • P2495 [SDOI2011]消耗战 虚树

    这是我做的第一道虚树题啊,赶脚不错.其实虚树也没什么奇怪的,就是每棵树给你一些点,让你多次查询,但是我不想每次都O(n),所以我们每次针对给的点建一棵虚树,只包含这些点和lca,然后在这棵虚树上进行树形dp,维护每个点的最小连边权值,这样的复杂度就会降低不少.这里我写了两种写法(其实都是抄的),一种是正常建树的正常做法,还有一种是不用建树,只用堆维护,模拟一棵树的操作,维护欧拉序,就是一个点有进入的编号,也有出去的编号.这样就可以不用真正建出虚树而能进行查询.

    题干:

    题目描述
    
    在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
    
    侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。
    输入输出格式
    输入格式:
    
    第一行一个整数n,代表岛屿数量。
    
    接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。
    
    第n+1行,一个整数m,代表敌方机器能使用的次数。
    
    接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。
    
    输出格式:
    
    输出有m行,分别代表每次任务的最小代价。
    
    输入输出样例
    输入样例#1: 复制
    
    10
    1 5 13
    1 9 6
    2 1 19
    2 4 8
    2 3 91
    5 6 8
    7 5 4
    7 8 31
    10 7 9
    3
    2 10 6
    4 5 7 8 3
    3 9 4 6
    
    输出样例#1: 复制
    
    12
    32
    22

    不用建树版本的代码:

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    #include<stack>
    using namespace std;
    #define duke(i,a,n) for(register int i = a;i <= n;i++)
    #define lv(i,a,n) for(register int i = a;i >= n;i--)
    #define clean(a) memset(a,0,sizeof(a))
    const long long INF = 1LL << 50;
    typedef long long ll;
    typedef double db;
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    const int N = 250010;
    struct node
    {
        int l,r,nxt;
        ll w;
    }a[2 * N];
    int lst[N],len = 0,n,m;
    void add(int x,int y,ll w)
    {
        a[++len].l = x;
        a[len].r = y;
        a[len].w = w;
        a[len].nxt = lst[x];
        lst[x] = len;
    }
    int dfin[N],cnt = 0,tr[4 * N],fa[N][22];
    int dep[N],dfout[N];
    ll mi[N],sum[N];
    bool book[N];
    stack <int> s;
    bool cmp(int x,int y)
    {
        int k1 = (x > 0) ? dfin[x] : dfout[-x];
        int k2 = (y > 0) ? dfin[y] : dfout[-y];
        return k1 < k2;
    }
    void dfs(int x)
    {
        dfin[x] = ++cnt;
        for(int i = 1;fa[x][i - 1];i++)
        {
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        }
        for(int k = lst[x];k;k = a[k].nxt)
        {
            int y = a[k].r;
            if(!dfin[y])
            {
                dep[y] = dep[x] + 1;
                mi[y] = min(mi[x],a[k].w);
                fa[y][0] = x;
                dfs(y);
            }
        }
        dfout[x] = ++cnt; 
        return;
    }
    int lca(int u,int v)
    {
        if(dep[u] < dep[v])
        swap(u,v);
        int del = dep[u] - dep[v];
        for(int i = 0;del;del >>= 1,i++)
        {
            if(del & 1)
            {
                u = fa[u][i];
            }
        }
        if(u == v) return u;
        for(int i = 20;i >= 0;i--)
        {
            if(fa[u][i] != fa[v][i])
            {
                u = fa[u][i];
                v = fa[v][i];
            }
        }
        return fa[v][0];
    }
    void cl_st()
    {
        stack <int> un;
        swap(un,s);
    }
    int main()
    {
        read(n);
        duke(i,1,n - 1)
        {
            int x,y,w;
            read(x);read(y);read(w);
            add(x,y,w);
            add(y,x,w);
        }
        mi[1] = INF;
        dfs(1);
        read(m);
        duke(i,1,m)
        {
            int cot = 0;
            cl_st();
    //        clean(tr);
            read(cot);
            duke(j,1,cot)
            {
                read(tr[j]);
                book[tr[j]] = true;
                sum[tr[j]] = mi[tr[j]];
            }
    //        cout<<"A"<<endl;
            sort(tr + 1,tr + cot + 1,cmp);
            duke(j,1,cot - 1)
            {
                int lc = lca(tr[j],tr[j + 1]);
    //            cout<<lc<<" "<<tr[j]<<" "<<tr[j + 1]<<endl;
                if(!book[lc])
                {
                    tr[++cot] = lc;
                    book[lc] = true;
                }
            }
    //        cout<<"B"<<endl;
            int nc = cot;
            for(int j = 1;j <= nc;j++)
            {
                tr[++cot] = -tr[j];
            }
            if(!book[1])
            {
                tr[++cot] = 1;
                tr[++cot] = -1;
            }
            sort(tr + 1,tr + cot + 1,cmp);
    //        cout<<"C"<<endl;
            duke(j,1,cot)
            {
    //            cout<<cot<<endl;
                if(tr[j] > 0)
                {
                    s.push(tr[j]);
                } 
                else
                {
                    int now = s.top();
                    s.pop();
    //                cout<<now<<endl; 
                    if(now != 1)
                    {
                        int f = s.top();
                        sum[f] += min(sum[now],mi[now]);
                    }
                    else
                    {
                        printf("%lld
    ",sum[1]);
                    }
                    sum[now] = 0;
                    book[now] = false;
                }
            }
        }
        return 0;
    }

    建树的代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<complex>
    #include<cstring>
    using namespace std;
    #define duke(i,a,n) for(int i = a;i <= n;i++)
    #define lv(i,a,n) for(int i = a;i >= n;i--)
    #define clean(a) memset(a,0,sizeof(a))
    #define mp make_pair
    #define cp complex<db>
    #define enter puts("")
    const long long INF = 1LL << 60;
    const double eps = 1e-8;
    typedef long long ll;
    typedef double db;
    template <class T>
    void read(T &x)
    {
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x)
    {
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    const int N = 250010;
    int n,dfn[N],tot = 0,cnt,m,_top;
    ll mn[N];
    int s[N];
    namespace T
    {
        struct node
        {
            int l,r,nxt,w;
        } a[2 * N];
        int lst[N],dep[N],f[N],tp[N],son[N],siz[N],len = 0;
        inline void add(int x,int y,int w)
        {
            a[++len].l = x;
            a[len].r = y;
            a[len].w = w;
            a[len].nxt = lst[x];
            lst[x] = len;
        }
        void dfs1(int u,int fa,int depth)
        {
            f[u] = fa;
            dep[u] = depth;
            siz[u] = 1;
            for(int k = lst[u];k;k = a[k].nxt)
            {
                int y = a[k].r;
                if(y == fa) continue;
                mn[y] = min(mn[u],(ll)a[k].w);
                dfs1(y,u,depth + 1);
                siz[u] += siz[y];
                if(son[u] == 0 || siz[son[u]] < siz[y])
                {
                    son[u] = y;
                }
            }
        }
        void dfs2(int u,int t)
        {
            dfn[u] = ++cnt;
            tp[u] = t;
            if(!son[u]) return;
            dfs2(son[u],t);
            for(int k = lst[u];k;k = a[k].nxt)
            {
                int y = a[k].r;
                if(y == f[u] || y == son[u]) continue;
                dfs2(y,y);
            }
        }
        inline int lca(int x,int y)
        {
            while(tp[x] != tp[y])
            {
                if(dep[tp[x]] < dep[tp[y]]) swap(x,y);
                x = f[tp[x]];
            }
            if(dep[x] > dep[y]) swap(x,y);
            return x;
        }
    }
    namespace ft
    {
        vector <int> v[N];
        void add(int x,int y)
        {
            v[x].push_back(y);
        }
        inline bool cmp(int a,int b)
        {
            return dfn[a] < dfn[b];
        }
        inline void ins(int x)
        {
            if(_top == 1)
            {
                s[++_top] = x; return;
            }
            int lca = T :: lca(x,s[_top]);
            // cout<<x<<" "<<s[_top]<<endl;
            if(lca == s[_top]) return;
            while(_top > 1 && dfn[s[_top - 1]] >= dfn[lca]) add(s[_top - 1],s[_top]),_top --;
            if(lca != s[_top]) add(lca,s[_top]),s[_top] = lca;
            s[++_top] = x;
        }
        ll pr(int x)
        {
            // printf("%d ",x);
            if(v[x].size() == 0) return mn[x];
            ll ans = 0;
            for(int i = 0;i < (int) v[x].size();i++)
            {
                int y = v[x][i];
                ans += pr(y);
            }
            v[x].clear();
            return min(ans,mn[x]);
        }
    }
    int a[N];
    int main()
    {
        // freopen("2495.in","r",stdin);
        read(n);
        memset(mn,0x3f,sizeof(mn));
        duke(i,1,n - 1)
        {
            int x,y,w;
            read(x);read(y);read(w);
            T :: add(x,y,w);
            T :: add(y,x,w);
        }
        T :: dfs1(1,0,1);
        T :: dfs2(1,1);
        /*duke(i,1,n)
        printf("%d ",dfn[i]);
        puts("");*/
        int x,y;
        read(m);
        while(m--)
        {
            int k;
            read(k);
            duke(i,1,k)
            read(a[i]);
            sort(a + 1,a + k + 1,ft :: cmp);
            s[_top = 1] = 1;
            duke(i,1,k)
            ft :: ins(a[i]);
            /*duke(i,1,_top)
            printf("%d ",s[i]);
            puts("");*/
            // cout<<n<<" ";
            /*duke(i,1,n)
            printf("%lld ",mn[i]);
            puts("");*/
            while(_top > 0) ft :: add(s[_top - 1],s[_top]),_top--;
            printf("%lld
    ",ft :: pr(1));
        }
        return 0;
    }
  • 相关阅读:
    2015个人年度总结
    矢量图标的使用
    onsrcoll和scrollTop兼容与实现
    我们,曾是阿里宝宝
    linux 基本操作笔记
    认识与学习shell
    两道有趣的面试题
    使用css保持一定宽高比例
    我在 超级课程表 实习的那个月
    3、4月学习总结,如愿阿里前端实习生
  • 原文地址:https://www.cnblogs.com/DukeLv/p/10112047.html
Copyright © 2011-2022 走看看