P2495 [SDOI2011]消耗战 虚树
Posted dukelv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于P2495 [SDOI2011]消耗战 虚树的主要内容,如果未能解决你的问题,请参考以下文章