洛谷 P2495 [SDOI2011]消耗战

题目描述

在一场战争中,战场由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

说明

【数据规模和约定】

对于10%的数据,2<=n<=10,1<=m<=5,1<=ki<=n-1

对于20%的数据,2<=n<=100,1<=m<=100,1<=ki<=min(10,n-1)

对于40%的数据,2<=n<=1000,m>=1,sigma(ki)<=500000,1<=ki<=min(15,n-1)

对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

这题没A,先放着,mlog^2n跑这个数据卡不过去

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <time.h>
#define eps 1e-7
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define rep0(j,n) for(int j=0;j<n;++j)
#define rep1(j,n) for(int j=1;j<=n;++j)
#define pb push_back
#define set0(n) memset(n,0,sizeof(n))
#define ll long long
#define ull unsigned long long
#define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0)
#define TO(j) printf(#j": %d\n",j);
//#define OJ
using namespace std;
const int MAXINT = 250010;
const int MAXNODE = 100010;
const int MAXEDGE = 2 * MAXNODE;
char BUF[30000000], *buf;
int read() {
    int x = 0;
    while (!isdigit(*buf)) buf++;
    while (isdigit(*buf)) { x = x * 10 + *buf++ - '0';}
    return x;
}
//------------------- Head Files ----------------------//
int toid[MAXINT];
struct res {
    int v, p;
    res(int _v, int _p) : v(_v), p(_p) {}
    res() {}
};

res add(res a, res b) {
    return (a.v < b.v ? a : b);
}
struct node {
    int lb, rb;
    node *l, *r;
    res ans, org;
    int del, cv, rec;
    inline void recover() __attribute__((optimize("-O2"))){
        del = 0;
        cv = INF;
        ans = org;
        rec = 1;
    }
    inline void cover(int c) __attribute__((optimize("-O2"))){
        cv = ans.v = c;
        if (del) del = 0;
    }
    inline void dec(int c) __attribute__((optimize("-O2"))){
        del += c;
        ans.v -= c;
    }
    inline void pushdown() __attribute__((optimize("-O2"))){
        if (rec) {
            l->recover(); r->recover();
            rec = 0;
        }
        if (cv != INF) {
            l->cover(cv); r->cover(cv);
            cv = INF;
        }
        if (del != 0) {
            l->dec(del);
            r->dec(del);
            del = 0;
        }
    }
    inline void pushup() __attribute__((optimize("-O2"))){
        ans = add(l->ans, r->ans);
    }
    node() {
        ans.v = del = cv = INF;
        rec = 0;
    }
};
int n, m, fa[MAXINT], sz[MAXINT], top[MAXINT], dfn[MAXINT], cnt_dfn = 1, dep[MAXINT], cnt, va[MAXINT], val[MAXINT], dfne[MAXINT];
struct SegTree {
    node mp[MAXINT * 4];
    node *root;
    int _cnt;
    SegTree() {
        _cnt = 0;
    }
    inline node *newnode(int l, int r) __attribute__((optimize("-O2"))){
        node *p = &mp[_cnt++];
        p->lb = l;
        p->rb = r;
        return p;
    }
    inline void maketree(int lb, int rb, node *&p) __attribute__((optimize("-O2"))){
        p = newnode(lb, rb);
        if (rb - lb > 1) {
            maketree(lb, (lb + rb) / 2, p->l);
            maketree((lb + rb) / 2, rb, p->r);
            p->pushup();
        }
        else {
            p->ans.v = val[p->lb];
            p->ans.p = lb;
        }
        p->org = p->ans;
    }
    inline void del(int lb, int rb, int c) __attribute__((optimize("-O2"))){
        del(lb, rb, c, root);
    }
    inline void del(int lb, int rb, int c, node *p) __attribute__((optimize("-O2"))){
        if (lb >= p->rb || rb <= p->lb) return;
        if (lb <= p->lb && rb >= p->rb) { p->dec(c); return; }
        p->pushdown();
        del(lb, rb, c, p->l);
        del(lb, rb, c, p->r);
        p->pushup();
    }
    inline void cover(int lb, int rb) __attribute__((optimize("-O2"))){
        cover(lb, rb, root);
    }
    inline void cover(int lb, int rb, node *p) __attribute__((optimize("-O2"))){
        if (lb >= p->rb || rb <= p->lb) return;
        if (lb <= p->lb && rb >= p->rb) { p->cover(0); return; }
        p->pushdown();
        cover(lb, rb, p->l);
        cover(lb, rb, p->r);
        p->pushup();
    }
    inline res query(int lb, int rb) __attribute__((optimize("-O2"))){
        return query(lb, rb, root);
    }
    inline res query(int lb, int rb, node *p) __attribute__((optimize("-O2"))){
        if (lb >= p->rb || rb <= p->lb) return res(INF, INF);
        if (lb <= p->lb && rb >= p->rb) return p->ans;
        p->pushdown();
        return add(query(lb, rb, p->l), query(lb, rb, p->r));
    }
    inline void recover() __attribute__((optimize("-O2"))){
        root->recover();
    }
} st;

struct edge {
    int u, v, l;
    edge *nxt;
    edge() {}
    edge(int _u, int _v, int _l, edge *_nxt) : u(_u), v(_v), l(_l), nxt(_nxt) {}
} mp[MAXINT * 2], *head[MAXINT];
inline void addedge(int u, int v, int l) {
    mp[cnt] = edge(u, v, l, head[u]);
    head[u] = &mp[cnt++];
    mp[cnt] = edge(v, u, l, head[v]);
    head[v] = &mp[cnt++];
}
inline void dfs1(int p) {
    sz[p] = 1;
    iter(i, p) {
        if (i->v == fa[p])continue;
        fa[i->v] = p; dep[i->v] = dep[p] + 1; va[i->v] = i->l;
        dfs1(i->v);
        sz[p] += sz[i->v];
    }
}
inline void dfs2(int p) {
    int mx = 0, gs = 0;
    dfn[p] = cnt_dfn++;
    iter(i, p) {
        if (i->v == fa[p]) continue;
        if (sz[i->v] > mx) {
            mx = sz[i->v];
            gs = i->v;
        }
    }
    if (gs == 0) return;
    top[gs] = top[p];
    dfs2(gs);
    iter(i, p) {
        if (i->v == fa[p] || i->v == gs) continue;
        top[i->v] = i->v;
        dfs2(i->v);
    }
    dfne[p] = cnt_dfn;
}
inline void modify(int l, int r, int c) {
    while (top[l] != top[r]) {
        if (dep[top[l]] > dep[top[r]]) {
            st.del(dfn[top[l]], dfn[l] + 1, c, st.root);
            l = fa[top[l]];
        }
        else {
            st.del(dfn[top[r]], dfn[r] + 1, c, st.root);
            r = fa[top[r]];
        }
    }
    st.del(min(dfn[r], dfn[l]), max(dfn[r], dfn[l]) + 1, c, st.root);
}
inline void cover(int p) {
    st.cover(dfn[p], dfne[p]);
}
inline res query(int l, int r) {
    res ans(INF, INF);
    while (top[l] != top[r]) {
        if (dep[top[l]] > dep[top[r]]) {
            ans = add(st.query(dfn[top[l]], dfn[l] + 1), ans);
            l = fa[top[l]];
        }
        else {
            ans = add(st.query(dfn[top[r]], dfn[r] + 1), ans);
            r = fa[top[r]];
        }
    }
    ans = add(st.query(min(dfn[r], dfn[l]), max(dfn[r], dfn[l]) + 1), ans);
    return ans;
}
inline void get_input() __attribute__((optimize("-O2")));
inline void work() __attribute__((optimize("-O2")));
int main() {
    get_input();
    work();
    return 0;
}
inline void work() {
    dfs1(1);
    dfs2(1);
    rep1(i, n) val[dfn[i]] = va[i];
    rep1(i, n) toid[dfn[i]] = i;
    val[1] = INF;
    st.maketree(1, n + 1, st.root);
    while (m--) {
        st.recover();
        int k = read();
        ll ans = 0;
        while (k--) {
            int p = read();
            res ret = query(1, p);
            ans += ret.v;
            cover(toid[ret.p]);
            modify(1, fa[toid[ret.p]], ret.v);
        }
        printf("%lld\n", ans);
    }
}
inline void get_input() {
    BUF[fread(BUF, 1, 30000000, stdin)] = '\0';
    buf = BUF;
    n = read();
    rep0(i, n - 1) {
        int u = read(), v = read(), l = read();
        addedge(u, v, l);
    }
    m = read();
}
/*
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
1
4 5 7 8 3
*/

 

转载于:https://www.cnblogs.com/LoveYayoi/p/6917904.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值