Codeforces 1088F(貪心+倍增)
阿新 • • 發佈:2018-12-15
題意
構造一顆樹使得滿足計算方法的結果最小。
思路
考慮兩棵樹,一棵為題目中的詢問構成的樹T1,一棵為要構造的滿足最終答案的樹T2。從T1點權最小的點向外構造T2,在T1中倍增預處理出祖先,每次選取結果最小的作為對答案的貢獻,在T2中讓當前點連上這個祖先。由於點權最小的點為根,所以構造的過程中當前點始終滿足點權大於父節點。
程式碼
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include <map> #include <set> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <cassert> #include <cstring> #include <iostream> #include <algorithm> #define IOS ios::sync_with_stdio(0),cin.tie(0); #define DBG(x) cerr << #x << " = " << x << endl; using namespace std; typedef long long LL; typedef long double LD; typedef unsigned long long ULL; const int inf = 0x3f3f3f3f; const int mod = 1000000007; const double eps = 1e-8; const double pi = acos(-1.0); void file(){ freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); } const int maxn = 5e5+5; const int maxm = 1e6+5; int n; int fa[maxn][25]; int tot,head[maxn]; LL minn=inf,pos,ans; LL a[maxn]; struct edgenode{ int to,next; }edge[maxm]; void addedge(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void dfs(int x,int pre){ fa[x][0]=pre; for(int i=1;i<=20;i++)fa[x][i]=fa[fa[x][i-1]][i-1]; if(x != pre){ LL tmp=a[pre]; for(int i=1;i<=20;i++)tmp=min(tmp,a[fa[x][i]]*1LL*(i+1)); ans+=a[x]+tmp; } for(int i=head[x];i != -1;i=edge[i].next){ int v=edge[i].to; if(v != pre)dfs(v,x); } } namespace BakuretsuMahou{ void Explosion(){ memset(head,-1,sizeof head); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%I64d",&a[i]); if(a[i] < minn){ minn=a[i]; pos=i; } } for(int i=1,x,y;i<=n-1;i++){ scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } dfs(pos,pos); printf("%I64d\n",ans); } } int main(){ //IOS //file(); BakuretsuMahou::Explosion(); return 0; }