hdu 6201 樹分治
阿新 • • 發佈:2018-12-01
題意:一棵樹,邊全,點權,點權是書的價格,邊權是運費。任選兩個點買賣,求最大 利益。
思路:nlogn樹分治,當時一看1e5,又是求樹上路徑的,想也沒想直接莽分治,分治的過程中維護最大作為買和賣的利益就好了。
程式碼:
#include<bits/stdc++.h> using namespace std; #define X first #define Y second #define PB push_back #define MP make_pair #define MEM(a,b) memset(a,b,sizeof(a)) typedef long long ll; const ll mod = 1e9+7; const int maxn =1e6+10; int n,t; int ans,root,Max; struct node{ int v,next,w; }edge[maxn*2]; int head[maxn],tot,num1,num2; int si[maxn],maxv[maxn],vis[maxn];//vis標記重心 int dis[maxn],a[maxn],tmpsell,tmpbuy; void init(){ tot=ans=0;MEM(head,-1);MEM(vis,0); } void add_edge(int u,int v,int w){ edge[tot].v=v;edge[tot].w=w;edge[tot].next=head[u];head[u]=tot++; } //處理子樹的大小(固定) void dfssi(int u,int f){ si[u]=1; maxv[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==f||vis[v])continue; dfssi(v,u); si[u]+=si[v]; if(si[v]>maxv[u])maxv[u]=si[v]; } } //找重心(固定) void dfsroot(int r,int u,int f){ if(si[r]-si[u]>maxv[u])//si[r]-si[u]是u上面部分的樹的尺寸,跟u的最大孩子比,找到最大孩子的最小差值節點 maxv[u]=si[r]-si[u]; if(maxv[u]<Max)Max=maxv[u],root=u; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==f||vis[v])continue; dfsroot(r,v,u); } } //求每個點到u的距離(自定義) void dfsdis(int u,int d,int f){ tmpsell=min(tmpsell,d-a[u]); tmpbuy=min(tmpbuy,d+a[u]); for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v!=f&&!vis[v])//不跨過其他重心 dfsdis(v,d+edge[i].w,u); } } //分邊解決一個重心的答案(自定義) int calc(int u,int d){ int ret=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v,w=edge[i].w; if(!vis[v]){ tmpsell=tmpbuy=1e9+10000; dfsdis(v,w,0); ret=max(ret,-a[u]-tmpsell); ret=max(ret,a[u]-tmpbuy); ret=max(ret,-tmpsell-tmpbuy); } } return ret; } void dfs(int u){ Max=n; dfssi(u,0);//重心預處理 dfsroot(u,u,0);//找重心 vis[root]=1; ans=max(ans,calc(root,0));//合併貢獻(固定?) for(int i=head[root];i!=-1;i=edge[i].next){ int v=edge[i].v; if(!vis[v])dfs(v); } } int main(){ scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int u,v,w; init(); for(int i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w);add_edge(v,u,w); } dfs(1); printf("%d\n",ans); } return 0; }