洛谷 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
*/
时间: 2024-11-09 05:50:15

洛谷 P2495 [SDOI2011]消耗战的相关文章

●洛谷P2495 [SDOI2011]消耗战

题链: https://www.luogu.org/problemnew/show/P2495题解: 虚树入门,树形dp 推荐博客:http://blog.csdn.net/lych_cys/article/details/50814948 代码: #include<bits/stdc++.h> #define MAXN 250005 #define INFll 0x3f3f3f3f3f3f3f3fll using namespace std; int N,Q,M; bool mark[MAX

luogu P2495 [SDOI2011]消耗战

二次联通门 : luogu P2495 [SDOI2011]消耗战 /* luogu P2495 [SDOI2011]消耗战 虚树+树形dp 首先对原图构建出虚树 在建图的时候处理出最小值 转移即可 小技巧 在dp的过程中可以顺便把边表清空 将边结构体封装可方便的建多张图 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define INF 1

AC日记——[SDOI2011]消耗战 洛谷 P2495

[SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 #define maxn 250005 #define ll long long #define maxm (maxn<<1) struct LandType { ll id,key; bool operator<(const LandType pos)const { return key

洛谷 P2486 [SDOI2011]染色

题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#1: 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q 3 5 C 5 1 2 Q 3 5 输出样例#1: 3 1 2 说明 题目大意:给一棵树,要求支持链覆盖+查询链上颜色段数 先考虑链上怎么做吧,颜色段数这个东西支持区间加,一个区间可以用三个属性表示:左端点的颜色,右端点的颜色,区间颜色段数 两段合并以后的颜色段数是:左段颜色段数+右

洛谷 P2487 [SDOI2011]拦截导弹

题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小.也就是拦截导弹的数量最多的方案.但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案

洛谷 P2488 [SDOI2011]工作安排

题目描述 你的任务是制定出一个产品的分配方案,使得订单条件被满足,并且所有员工的愤怒值之和最小.由于我们并不想使用Special Judge,也为了使选手有更多的时间研究其他两道题目,你只需要输出最小的愤怒值之和就可以了. 输入输出格式 输入格式: 输出格式: 仅输出一个整数,表示最小的愤怒值之和. 输入输出样例 输入样例#1: 2 3 2 2 2 1 1 0 0 0 1 1 2 1 10 1 2 1 6 输出样例#1: 24 说明 一看,哇,修车,美食节,直接拆点,跑费用流,光荣T掉,还WA了

P2495 [SDOI2011]消耗战 虚树

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

P2495 [SDOI2011]消耗战

传送门 虚树DP经典题 首先有一个显然的$O(nm)$的树形DP 以 1 号节点为根 设 $f [ x ]$ 表示把节点 $x$ 子树内的资源点都与 $x$ 的父节点断开的最小代价 那么转移显然: 枚举 $x$ 的所有儿子节点 $v$,设 $x$ 到父节点的边权为 $w$ $f [ x ] = min ( w,\sum_vf[v] )$ 然后发现 $\sum_{k_i}\leq 500000$ 所以显然要搞虚树 每次DP只要把有用的节点提出来,根据它们之间的父子关系建一颗虚树 DP只要在虚树上D

洛谷 P2486 BZOJ 2243 [SDOI2011]染色

题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. 输入输出格式 输入格式: 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n个节点的初始颜色 下面 行每行包含两个整数x和y,表示x和y之间有一条无向边. 下面 行每行描述一个操作: “C a