zoukankan      html  css  js  c++  java
  • bzoj4326

    二分+树剖+差分

    之前的做法naive,莫名其妙的wa,明明uoj95分

    看到最小最大上二分,树上路径问题直接剖,然后问题就转化成了一个判定问题,每次二分出最长路径长度,问能不能达到。那么我们就把所有长度大于二分出的d的路径拉出来,求出他们公共路径的最大长度,看减去能不能满足。那么现在的问题就转化成了求路径的交。我们可以利用bzoj4390的树上差分的方法解决,我们先把边转化为点,即每条边等价于他连接的深度较深的点,那么我们利用树上差分标记路径上的边,把路径上的边标记+1,这个我们只要在u,v,+1,lca,-2就行了,然后我们求一个前缀和,看子树权值是否等于路径数量就行了。

    树上差分是一种重要的思想,大概有几种方法,

    1.像这道题和bzoj4390,可以标记路径上的点/边

    2.像noip2016day1t2,雨天的尾巴,利用树剖重链是一段连续的区间且最多只有log条重链,我们可以log时间修改路径的信息,这和上面的差分是不一样的,因为如果按上面的方法差分那么可能会把这条路径上的信息带到其他的点,而树剖保证dfs序连续,所以每条重链差分一下,那么就不会带入到其他点,这样一共会打logn个标记

    原先是像魔法森林那样把边权转化为点权,时间爆炸

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 300010;
    struct edge {
        int nxt, to, w;
    } e[N << 1];
    struct path {
        int u, v, w;
        bool friend operator < (path a, path b) { return a.w > b.w; }
    } a[N];
    namespace IO 
    {
        const int Maxlen = N * 50;
        char buf[Maxlen], *C = buf;
        int Len;
        inline void read_in()
        {
            Len = fread(C, 1, Maxlen, stdin);
            buf[Len] = '';
        }
        inline void fread(int &x) 
        {
            x = 0;
            int f = 1;
            while (*C < '0' || '9' < *C) { if(*C == '-') f = -1; ++C; }
            while ('0' <= *C && *C <= '9') x = (x << 1) + (x << 3) + *C - '0', ++C;
            x *= f;
        }
        inline void read(int &x)
        {
            x = 0;
            int f = 1; char c = getchar();
            while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
            while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + c - '0'; c = getchar(); }
            x *= f;
        }
        inline void read(long long &x)
        {
            x = 0;
            long long f = 1; char c = getchar();
            while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
            while(c >= '0' && c <= '9') { x = (x << 1ll) + (x << 3ll) + c - '0'; c = getchar(); }
            x *= f;
        } 
    } using namespace IO;
    int n, m, cnt = 1, tot, lim;
    int tree[N], mark[N], mir[N], head[N], dis[N], size[N], son[N], dep[N], fa[N], top[N], Lca[N], w[N], in[N], out[N];
    void link(int u, int v, int w)
    {
        e[++cnt].nxt = head[u];
        head[u] = cnt;
        e[cnt].to = v;
        e[cnt].w = w;
    }
    void dfs(int u, int last)
    {
        size[u] = 1;
        dis[u] = dis[last] + w[u];
        for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last)
        {
            dep[e[i].to] = dep[u] + 1;
            fa[e[i].to] = u;
            w[e[i].to] = e[i].w;
            dfs(e[i].to, u);
            size[u] += size[e[i].to];
            if(size[e[i].to] > size[son[u]]) son[u] = e[i].to;
        }
    }
    void dfs(int u, int acs, int last)
    {
        in[u] = ++tot;
        mir[tot] = u;
        top[u] = acs;
        if(son[u]) dfs(son[u], acs, u);
        for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last && e[i].to != son[u]) dfs(e[i].to, e[i].to, u);
        out[u] = tot;
    }
    int lca(int u, int v)
    {
        while(top[u] != top[v])
        {
            if(dep[top[u]] < dep[top[v]]) swap(u, v);
            u = fa[top[u]];
        }
        return dep[u] < dep[v] ? u : v;
    }
    int Dis(int u, int v)
    {
        int x = lca(u, v);
        return dis[u] + dis[v] - 2 * dis[x]; 
    }
    void update(int x, int d)
    {
        for(; x <= n; x += x & (-x)) tree[x] += d;
    }
    int query(int x)
    {
        int ret = 0;
        for(; x; x -= x & (-x)) ret += tree[x];
        return ret;
    }
    bool check(int d)
    {
        memset(mark, 0, sizeof(mark));
        int cou = 0, mx = 0;
        for(int i = 1; i <= m; ++i) 
        {
            if(a[i].w <= d) break;
            ++cou;
            mark[in[Lca[i]]] -= 2;
            ++mark[in[a[i].u]];
            ++mark[in[a[i].v]];
        }
        for(int i = 1; i <= n; ++i) mark[i] += mark[i - 1];
        for(int i = 1; i <= n; ++i) 
        {
            int tmp = mark[out[i]] - mark[in[i] - 1];
            if(tmp == cou) mx = max(mx, w[i]);
        }    
        return a[1].w - mx <= d;
    }
    int main()
    {
        read_in();
        fread(n);
        fread(m);
        for(int i = 1; i < n; ++i)
        {
            int u, v, w;
            fread(u);
            fread(v);
            fread(w);
            link(u, v, w);
            link(v, u, w);
        }
        dfs(1, 0);
        dfs(1, 1, 0);
        for(int i = 1; i <= m; ++i) 
        {
            fread(a[i].u);
            fread(a[i].v);
            a[i].w = Dis(a[i].u, a[i].v);
            lim = max(lim, a[i].w);
        }    
        sort(a + 1, a + m + 1);
        for(int i = 1; i <= m; ++i) Lca[i] = lca(a[i].u, a[i].v);
        int l = -1, r = lim + 1, ans = 0;
        while(r - l > 1)
        {
            int mid = (l + r) >> 1;
            if(check(mid)) r = ans = mid;
            else l = mid;
        }
        printf("%d
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    AngularJS 国际化——Angular-translate
    Elasticsearch Span Query跨度查询
    Elasticsearch 连接查询
    Elasticsearch DSL中Query与Filter的不同
    Lucene查询语法详解
    Elasticsearch 文件目录解释
    Elasticsearch 安装与启动
    《大屏可视化数据》该怎么设计?
    两个大屏可视化案例的布局与实现
    maven 安装后变成 mvn 不是内部命令解决方法
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7525704.html
Copyright © 2011-2022 走看看