P2495 [SDOI2011]消耗戰 虛樹
阿新 • • 發佈:2018-12-13
一道 什麽 隨機 查詢 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 79 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> usingnamespace 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]消耗戰 虛樹