1. 程式人生 > >P2495 [SDOI2011]消耗戰 虛樹

P2495 [SDOI2011]消耗戰 虛樹

一道 什麽 隨機 查詢 names amp cout queue 輸入

這是我做的第一道虛樹題啊,趕腳不錯.其實虛樹也沒什麽奇怪的,就是每棵樹給你一些點,讓你多次查詢,但是我不想每次都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\n",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\n",ft :: pr(1));
    }
    return 0;
}

P2495 [SDOI2011]消耗戰 虛樹