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<=。 第n+1行,一个整数m,代表敌方机器能使用的次数。 接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。 输出格式: 输出有m行,分别代表每次任务的最小代价。 输入输出样例
输入样例#: 复制 输出样例#: 复制
不用建树版本的代码:
// 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 << ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
const int N = ;
struct node
{
int l,r,nxt;
ll w;
}a[ * N];
int lst[N],len = ,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 = ,tr[ * N],fa[N][];
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 > ) ? dfin[x] : dfout[-x];
int k2 = (y > ) ? dfin[y] : dfout[-y];
return k1 < k2;
}
void dfs(int x)
{
dfin[x] = ++cnt;
for(int i = ;fa[x][i - ];i++)
{
fa[x][i] = fa[fa[x][i - ]][i - ];
}
for(int k = lst[x];k;k = a[k].nxt)
{
int y = a[k].r;
if(!dfin[y])
{
dep[y] = dep[x] + ;
mi[y] = min(mi[x],a[k].w);
fa[y][] = 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 = ;del;del >>= ,i++)
{
if(del & )
{
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = ;i >= ;i--)
{
if(fa[u][i] != fa[v][i])
{
u = fa[u][i];
v = fa[v][i];
}
}
return fa[v][];
}
void cl_st()
{
stack <int> un;
swap(un,s);
}
int main()
{
read(n);
duke(i,,n - )
{
int x,y,w;
read(x);read(y);read(w);
add(x,y,w);
add(y,x,w);
}
mi[] = INF;
dfs();
read(m);
duke(i,,m)
{
int cot = ;
cl_st();
// clean(tr);
read(cot);
duke(j,,cot)
{
read(tr[j]);
book[tr[j]] = true;
sum[tr[j]] = mi[tr[j]];
}
// cout<<"A"<<endl;
sort(tr + ,tr + cot + ,cmp);
duke(j,,cot - )
{
int lc = lca(tr[j],tr[j + ]);
// 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 = ;j <= nc;j++)
{
tr[++cot] = -tr[j];
}
if(!book[])
{
tr[++cot] = ;
tr[++cot] = -;
}
sort(tr + ,tr + cot + ,cmp);
// cout<<"C"<<endl;
duke(j,,cot)
{
// cout<<cot<<endl;
if(tr[j] > )
{
s.push(tr[j]);
}
else
{
int now = s.top();
s.pop();
// cout<<now<<endl;
if(now != )
{
int f = s.top();
sum[f] += min(sum[now],mi[now]);
}
else
{
printf("%lld\n",sum[]);
}
sum[now] = ;
book[now] = false;
}
}
}
return ;
}
建树的代码:
#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 << ;
const double eps = 1e-;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
const int N = ;
int n,dfn[N],tot = ,cnt,m,_top;
ll mn[N];
int s[N];
namespace T
{
struct node
{
int l,r,nxt,w;
} a[ * N];
int lst[N],dep[N],f[N],tp[N],son[N],siz[N],len = ;
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] = ;
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 + );
siz[u] += siz[y];
if(son[u] == || 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 == )
{
s[++_top] = x; return;
}
int lca = T :: lca(x,s[_top]);
// cout<<x<<" "<<s[_top]<<endl;
if(lca == s[_top]) return;
while(_top > && dfn[s[_top - ]] >= dfn[lca]) add(s[_top - ],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() == ) return mn[x];
ll ans = ;
for(int i = ;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,,n - )
{
int x,y,w;
read(x);read(y);read(w);
T :: add(x,y,w);
T :: add(y,x,w);
}
T :: dfs1(,,);
T :: dfs2(,);
/*duke(i,1,n)
printf("%d ",dfn[i]);
puts("");*/
int x,y;
read(m);
while(m--)
{
int k;
read(k);
duke(i,,k)
read(a[i]);
sort(a + ,a + k + ,ft :: cmp);
s[_top = ] = ;
duke(i,,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 > ) ft :: add(s[_top - ],s[_top]),_top--;
printf("%lld\n",ft :: pr());
}
return ;
}
P2495 [SDOI2011]消耗战 虚树的更多相关文章
- luogu P2495 [SDOI2011]消耗战 |虚树+LCA+dp
题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...
- bzoj 2286: [Sdoi2011]消耗战 虚树+树dp
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- 【BZOJ2286】[Sdoi2011]消耗战 虚树
[BZOJ2286][Sdoi2011]消耗战 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的 ...
- bzoj 2286(洛谷 2495) [Sdoi2011]消耗战——虚树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2286 https://www.luogu.org/problemnew/show/P2495 ...
- BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)
题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- [SDOI2011]消耗战(虚树+树形动规)
虚树dp 虚树的主要思想: 不遍历没用的的节点以及没用的子树,从而使复杂度降低到\(\sum\limits k\)(k为询问的节点的总数). 所以怎么办: 只把询问节点和其LCA放入询问的数组中. 1 ...
随机推荐
- js中=,==,===的区别
= 赋值 == 先判断类型,在判断值,可以做类型转换 === 恒等判断
- HDU-4705 Y(思维+dfs树)
Input 4 1 2 1 3 1 4 Output 1 题意:给你一颗树,选择一个三个点构成的集合,使得这三个点不在一条直线上(意思就是 从一个点出发,用一条不回头的线不能将这三个点连起来)问一共有 ...
- 手动模拟一个类似jquery的ajax请求
var $ = { parms:function(obj){ var str = ''; for(var k in obj){ str +=k+'='+obj[k]+'&'; } str = ...
- [转] 探讨JS合并两个数组的方法
我们在项目过程中,有时候会遇到需要将两个数组合并成为一个的情况. 比如: 1 2 var a = [1,2,3]; var b = [4,5,6]; 有两个数组a.b,需求是将两个数组合并成一个.方法 ...
- 【16】AngularJS API
AngularJS API API 意为 Application Programming Interface(应用程序编程接口). AngularJS 全局 API AngularJS 全局 API ...
- 【Codeforces 242C】King's Path
[链接] 我是链接,点我呀:) [题意] 让你找到(x0,y0)到(x1,y1)的一条最短路 走过的点必须在所给的n个横向路径上 [题解] 因为n条横向路径上的点最多不会超过10的5次方个,所以我们可 ...
- SQL to MongoDB Mapping Chart
http://docs.mongodb.org/manual/reference/sql-comparison/ In addition to the charts that follow, you ...
- python整数转ASCII码
# *-* coding:utf-8 *-* import binascii data = [1441465642, 251096121, -870437532, -944322827, 647240 ...
- 【BZOJ4514】数字配对(费用流)
题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci× ...
- Win32编程API 基础篇 -- 4.消息循环
消息循环 理解消息循环 为了编写任何即使是最简单的程序,了解windows程序的消息循环和整个消息发送结构是非常有必要的.既然我们已经尝试了一点消息处理的东西,我们应该对整个程序有更深入的理解,如果你 ...