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;
}
View Code

 

posted @ 2017-06-03 22:54  Galaxies  阅读(684)  评论(0编辑  收藏  举报