1. 程式人生 > >【點分治】【資料結構】Codeforces1019E Raining season

【點分治】【資料結構】Codeforces1019E Raining season

題意:

給出一棵樹,每條邊的距離都是一個一次函式,給出斜率k和截距m。(y=k*x+m)
現在求當x=0,1,2,……,t-1時,整個圖中最遠點的距離。

分析:

這題一股濃郁的OI氣息啊。。。(思路簡單實現複雜的資料結構題)

首先,如果不考慮那個神奇的邊權,那麼就是一個簡單的點分治水題。。。

現在考慮加上這個邊權,很容易發現,最終答案一定是一個下凸殼。

所以可以用一個multiset維護這個凸殼中的所有邊,以及邊之間的交點。由於每層有n個葉子節點,然後有logn層,所以總共的線段數不超過nlogn。。。

具體實現看程式碼吧,註釋應該夠詳細了

#include<cstdio>
#include<cstring> #include<algorithm> #include<set> #include<vector> #define SF scanf #define PF printf #define MAXN 100010 #define INF 0x3FFFFFFF using namespace std; typedef long long ll; typedef pair<ll,ll> pll; bool Q; struct Line{ mutable ll k,m,p;//slope,intercept,intersection
Line () {} Line (ll k1,ll m1,ll p1):k(k1),m(m1),p(p1) {} bool operator < (const Line & a) const { if(Q==1) return p<a.p; else return k<a.k; } }; typedef multiset<Line>::iterator mult ; struct LC : multiset<Line>{//maintain the lines,sperated by the intersection
ll inf=1ll*INF*INF; ll flr(ll a,ll b){ if((a^b)<0) return a/b-((a%b)!=0); else return a/b; } bool compare(iterator x,iterator y){//check: whether the x cover y or not (Slope of x is not bigger than y) if(y==end()){//y is the end of the set x->p=inf; return 0; } if(x->k==y->k){//compare the intercept if(x->m>y->m) x->p=inf; else x->p=-inf; } else x->p=flr(y->m - x->m,x->k - y->k); return x->p >= y->p; } void add(ll k,ll m){//add the line with slope = k ,intercept = m in the set multiset<Line>::iterator z=insert(Line(k,m,0)); multiset<Line>::iterator y=z++; multiset<Line>::iterator x=y; while(compare(y,z))//compare the latter z=erase(z); if(x!=begin()&&compare(--x,y)){//get the intersection y=erase(y); compare(x,y); } y=x; while(y!=begin()&&(--x)->p>=y->p){//compare the former y=erase(y); compare(x,y); y=x; } } ll que(ll x){ Q=1; mult l=lower_bound(Line(0,0,x)); Q=0; return l->k*x+l->m; } }ans; vector<int> a[MAXN]; vector<ll> K[MAXN],M[MAXN]; int siz[MAXN]; bool vis[MAXN]; int cent=-1,mins; int dfs(int x,int fa){ siz[x]=1; for(int i=0;i<a[x].size();i++){ int u=a[x][i]; if(u==fa||vis[u]) continue; siz[x]+=dfs(u,x); } return siz[x]; } void find_c(int x,int fa,int sum){ int mxsiz=sum-siz[x]; for(int i=0;i<a[x].size();i++){ int u=a[x][i]; if(u==fa||vis[u]) continue; mxsiz=max(mxsiz,siz[u]); find_c(u,x,sum); } if(cent==-1||mins>mxsiz){ mins=mxsiz; cent=x; } } int get_c(int x){ if(vis[x]==1) return -1; cent=-1; mins=0; int sum=dfs(x,-1); find_c(x,-1,sum); return cent; } vector<pll> ans1; void update_ans(const LC &a,const LC &b){//merge and use them to update ans vector<pll> linea,lineb; for(mult it=a.begin();it!=a.end();it++){ if(linea.size()>0&&linea[linea.size()-1].first==it->k){ linea[linea.size()-1].second=max(linea[linea.size()-1].second,it->m); continue; } linea.push_back(make_pair(it->k,it->m)); } for(mult it=b.begin();it!=b.end();it++){ if(lineb.size()>0&&lineb[lineb.size()-1].first==it->k){ lineb[lineb.size()-1].second=max(lineb[lineb.size()-1].second,it->m); continue; } lineb.push_back(make_pair(it->k,it->m)); } int l=0,r=0; while(l<linea.size()&&r<lineb.size()){ ans1.push_back(make_pair(linea[l].first+lineb[r].first,linea[l].second+lineb[r].second)); if(l+1==linea.size()) r++; else if(r+1==lineb.size()) l++; else{ double p1=-(double)(linea[l+1].second-linea[l].second)/(double)(linea[l+1].first-linea[l].first); double p2=-(double)(lineb[r+1].second-lineb[r].second)/(double)(lineb[r+1].first-lineb[r].first); if(p1<p2) l++; else r++; } } } LC merge_trees(int l,int r,vector<LC> & s){//merge the route from the different trees if(l==r){ LC l0; l0.add(0,0); update_ans(l0,s[l]); return s[l]; } else{ int mid=(l+r)>>1; LC l1=merge_trees(l,mid,s); LC l2=merge_trees(mid+1,r,s); update_ans(l1,l2); for(mult it=l1.begin();it!=l1.end();it++) l2.add(it->k,it->m); return l2; } } LC li; void get_l(int x,int fa,ll prk,ll prm){//dfs in the tree bool flag=0; for(int i=0;i<a[x].size();i++){ int u=a[x][i]; if(u==fa||vis[u]) continue; get_l(u,x,prk+K[x][i],prm+M[x][i]); flag=1; } if(!flag){ li.add(prk,prm);//only the leaf can be the best } } void solve(int x){//solve the subtree with vertex x int centroid=get_c(x); if(centroid==-1) return ; vector<LC> s; for(int i=0;i<a[centroid].size();i++){ int u=a[centroid][i]; if(vis[u]) continue; li.add(0,0); get_l(u,centroid,K[centroid][i],M[centroid][i]); s.push_back(li); li.clear(); } if(s.size()>0) merge_trees(0,s.size()-1,s); vis[centroid]=1; for(int i=0;i<a[centroid].size();i++){ int u=a[centroid][i]; if(!vis[u]) solve(u); } } int n,t,u,v,k1,m1; int main(){ SF("%d%d",&n,&t); for(int i=1;i<n;i++){ SF("%d%d%d%d",&u,&v,&k1,&m1); a[u].push_back(v); a[v].push_back(u); K[u].push_back(k1); K[v].push_back(k1); M[u].push_back(m1); M[v].push_back(m1); } solve(1); ans.add(0,0); for(int i=0;i<ans1.size();i++) ans.add(ans1[i].first,ans1[i].second); for(int i=0;i<t;i++) PF("%I64d ",ans.que(i)); }