bzoj1758 [Wc2010]重建计划
Posted 逢山开路 遇水架桥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1758 [Wc2010]重建计划相关的知识,希望对你有一定的参考价值。
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1758
【题解】
一看就知道是分数规划问题就二分了。
权值全部扣去二分的值x,转成判断是否存在L<=len<=U的路径,权值和>=0
这就是一个点分的问题了。
已经有一个二分了所以里面的点分只允许有一个log。我们需要线性合并这玩意儿。。
我们想到了单调队列,我们很容易合并两个大小为深度的数组。
然后想都不想直接交了一发,TLE?
(这时候确实是对的)
然后看了看网上的题解,因为二分过程中,每次点分的root是一样的,一直找很麻烦,所以我们可以提前处理好这个root。
第一发写在了二分判断里了(那跟没写一样),后来写对完交了已发,还是TLE?
打开discuss一看,这个加强数据的人怎么这样啊,不过也好,给了我很深的印象,以后会注意到这个的。
写点分治的时候,如果合并涉及到子树合并,且合并的两个数组的大小为子树的深度和总深度,那么需要按子树深度从小到大合并。
这样才能保证复杂度,其实这个tips之前有看到过(做codechef的primedst的时候)
那么这么写完就过了,加了快读27s,这卡常题。。。卧槽怎么5k了。。
# include <vector> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; const double eps = 1e-7; # define RG register # define ST static namespace FIFO { char ch,B[1<<20],*S=B,*T=B; #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<20,stdin),S==T)?0:*S++) #define isd(c) (c>=‘0‘&&c<=‘9‘) int aa,bb;int F(){ while(ch=getc(),!isd(ch)&&ch!=‘-‘);ch==‘-‘?aa=bb=0:(aa=ch-‘0‘,bb=1); while(ch=getc(),isd(ch))aa=aa*10+ch-‘0‘;return bb?aa:-aa; } } #define gi FIFO::F() #define BUFSIZE 5000000 namespace fob {char b[BUFSIZE]={},*f=b,*g=b+BUFSIZE-2;} #define pob (fwrite(fob::b,sizeof(char),fob::f-fob::b,stdout),fob::f=fob::b,0) #define pc(x) (*(fob::f++)=(x),(fob::f==fob::g)?pob:0) struct foce {~foce() {pob; fflush(stdout);}} _foce; namespace ib {char b[100];} inline void pint(int x) { if(x==0) {pc(48); return;} //if(x<0) {pc(‘-‘); x=-x;} //如果有负数就加上 char *s=ib::b; while(x) *(++s)=x%10, x/=10; while(s!=ib::b) pc((*(s--))+48); } int n, L, U, tot, rtn; const double mINF = -1e18; ST int head[M], nxt[M], to[M], w[M], rt[M]; inline void add(int u, int v, int _w) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; w[tot] = _w; } inline void adde(int u, int v, int _w) { add(u, v, _w), add(v, u, _w); } struct pa { int a, b; pa() {} pa(int a, int b) : a(a), b(b) {} }; namespace DFZ { bool ok; double SUB; ST bool vis[M]; ST int sz[M], mx[M]; int mi, centre; void dfsSize(int x, int fa=0) { sz[x] = 1; mx[x] = 0; for (RG int i=head[x]; i; i=nxt[i]) { if(to[i] == fa || vis[to[i]]) continue; dfsSize(to[i], x); sz[x] += sz[to[i]]; if(sz[to[i]] > mx[x]) mx[x] = sz[to[i]]; } } void dfsCentre(int x, int tp, int fa=0) { if(sz[tp] - sz[x] > mx[x]) mx[x] = sz[tp] - sz[x]; if(mx[x] < mi) mi = mx[x], centre = x; for (RG int i=head[x]; i; i=nxt[i]) { if(to[i] == fa || vis[to[i]]) continue; dfsCentre(to[i], tp, x); } } inline int getdep(int x, int fa=0) { int ret = 0; for (RG int i=head[x], t; i; i=nxt[i]) { if(to[i] == fa || vis[to[i]]) continue; if((t = getdep(to[i], x)) > ret) ret = t; } return ret + 1; } ST int q[M]; ST double f[M], g[M]; int fn, gn; void getAns(int x, int fa, double ww, int d) { if(d > U) return ; if(d > gn) gn = d; if(ww > g[d]) g[d] = ww; for (RG int i=head[x]; i; i=nxt[i]) { if(to[i] == fa || vis[to[i]]) continue; getAns(to[i], x, ww+w[i]-SUB, d+1); } } vector< pa > son[M]; inline void calc(int x) { // cout << "x=" << x << endl; RG int mxdep = 0, dep; fn = 0; f[0] = 0; for (RG int i=head[x]; i; i=nxt[i]) { if(vis[to[i]]) continue; dep = getdep(to[i], x); son[dep].push_back(pa(to[i], w[i])); if(dep > mxdep) mxdep = dep; } for (RG int i=0; i<=mxdep; ++i) { if(!ok) for (RG int p=0; p<son[i].size(); ++p) { int y = son[i][p].a;// cout << y << endl; gn = 0; g[0] = 0; getAns(y, x, son[i][p].b-SUB, 1); RG int b = gn, head = 1, tail = 0; for (RG int a=0; a<=fn; ++a) { while(b >= 0 && a+b >= L) { while(head <= tail && a+q[head] > U) ++head; while(head <= tail && g[q[tail]] < g[b]) --tail; q[++tail] = b; --b; } if(head <= tail && g[q[head]] + f[a] > -eps) { ok = 1; for (int j=0; j<=fn; ++j) f[j] = mINF; for (int j=0; j<=gn; ++j) g[j] = mINF; goto here; } } if(fn < gn) fn = gn; for (RG int j=0; j<=gn; ++j) if(f[j] < g[j]) f[j] = g[j]; for (RG int j=0; j<=gn; ++j) g[j] = mINF; } here:; son[i].clear(); } for (RG int j=0; j<=fn; ++j) f[j] = mINF; vis[x] = 1; } void dfs(int x) { dfsSize(x); mi = n; dfsCentre(x, x); x = centre; rt[++rtn] = x; vis[x] = 1; for (RG int i=head[x]; i; i=nxt[i]) if(!vis[to[i]]) dfs(to[i]); } inline bool main(double x) { SUB = x; ok = 0; for (RG int i=1; i<=n; ++i) vis[i] = 0; for (int i=1; i<=rtn; ++i) { calc(rt[i]); if(ok) return 1; } return 0; } } int main() { // freopen("bzoj1758.in", "r", stdin); double l = 0.0, r = -1e9, mid; n = gi; L = gi; U = gi; // cin >> n >> L >> U; for (RG int i=1, u, v, _w; i<n; ++i) { u = gi; v = gi;_w = gi; // scanf("%d%d%d", &u, &v, &_w); adde(u, v, _w); if(_w > r) r = _w; } for (RG int i=1; i<=n; ++i) DFZ::vis[i] = 0; DFZ::dfs(1); for (RG int i=0; i<=n; ++i) DFZ::f[i] = DFZ::g[i] = mINF; while(r-l > 1e-4) { mid = (l+r)/2.0; if(DFZ::main(mid)) l = mid; else r = mid; } printf("%.3lf\n", l); return 0; }
以上是关于bzoj1758 [Wc2010]重建计划的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check