zoukankan      html  css  js  c++  java
  • bzoj4009

    4009: [HNOI2015]接水果

    Time Limit: 60 Sec  Memory Limit: 512 MB
    Submit: 633  Solved: 299
    [Submit][Status][Discuss]

    Description

    风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。
    由于她已经DT FC 了The big black,  她觉得这个游戏太简单了,于是发明了一个更
    加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1
    给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条
    路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个
    盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),
    权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第
    i 个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水
    果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如
    图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与
    从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择
    能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数
    的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水
    果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? 
     

    Input

    第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。 

    接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点
    按1到 n标号。 接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其
    中0≤c≤10^9,a不等于b。 
    接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,
    第k 小一定存在。 
     

    Output

     对于每个果子,输出一行表示选择的盘子的权值。 

    Sample Input

    10 10 10
    1 2
    2 3
    3 4
    4 5
    5 6
    6 7
    7 8
    8 9
    9 10
    3 2 217394434
    10 7 13022269
    6 7 283254485
    6 8 333042360
    4 6 442139372
    8 3 225045590
    10 4 922205209
    10 8 808296330
    9 2 486331361
    4 9 551176338
    1 8 5
    3 8 3
    3 8 4
    1 8 3
    4 8 1
    2 3 1
    2 3 1
    2 3 1
    2 4 1
    1 4 1

    Sample Output

    442139372
    333042360
    442139372
    283254485
    283254485
    217394434
    217394434
    217394434
    217394434
    217394434

    HINT

    N,P,Q<=40000。 

    Source

    http://blog.csdn.net/thy_asdf/article/details/50363672

    前面的部分说的很详细了。但是写的时候要注意几点:

    1. 判断lca类型的时候u和v比较的是dfn大小,不是dep大小

    2.水果读入的时候如果dfn[x1] > dfn[y1] swap(x1, y1)

    3.整体二分里排序注意插入删除和水果的顺序

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 100010;
    int n, p, m, cnt, tot = 1, Time;
    struct E {
        int nxt, to;
    } e[N << 1];
    struct P {
        int x1, y1, x2, y2, w, id, k, type;
        P(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, int w = 0, int id = 0, int k = 0, int type = 0) : x1(x1), y1(y1), x2(x2), y2(y2), w(w), id(id), k(k), type(type) {}
    } event[N], q[N];
    struct BIT {
        int tree[N];
        int lowbit(int x) {return x&(-x);}
        void update(int l, int r, int v) 
        {
            for(int i = l; i <= n; i += lowbit(i)) tree[i] += v;
            for(int i = r + 1; i <= n; i += lowbit(i)) tree[i] -= v;
        }
        int query(int pos) {int ret = 0; for(int i = pos; i; i -= lowbit(i)) ret += tree[i]; return ret;}
    } t;
    vector<P> c, lp, rp; 
    int head[N], ans[N], low[N], dfn[N] ,fa[23][N], dep[N];
    void link(int u, int v)
    {
        e[++tot].nxt = head[u];
        head[u] = tot;
        e[tot].to = v;
    }
    bool cp(P i, P j) {return i.w < j.w;} 
    bool cp1(P i, P j) {return i.x1 == j.x1 ? i.type < j.type : i.x1 < j.x1;}
    void dfs(int u, int last)
    {
        dfn[u] = ++Time;
        for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last)
        {
            fa[0][e[i].to] = u;
            dep[e[i].to] = dep[u] + 1;
            dfs(e[i].to, u);
        }
        low[u] = Time;
    }
    int lca(int u, int v)
    {
        if(dep[u] < dep[v]) swap(u, v);
        for(int i = 22; i >= 0; --i) if((dep[u] - dep[v]) & (1 << i))
            u = fa[i][u];
        if(u == v) return u;
        for(int i = 22; i >= 0; --i) if(fa[i][u] != fa[i][v])
        {
            u = fa[i][u]; v = fa[i][v];
        }
        return fa[0][u];
    }
    int jump(int u, int h)
    {
        for(int i = 22; i >= 0; --i) if(h & (1 << i)) u = fa[i][u]; return u;
    }
    void solve(int l, int r, int lb, int rb)
    {
        if(l > r) return;
        if(lb == rb)
        {
            for(int i = l; i <= r; ++i) ans[q[i].id] = event[lb].w;
            return;
        }
        int mb = (lb + rb) >> 1;
        c.clear(); lp.clear(); rp.clear();
        for(int i = lb; i <= mb; ++i)
        {//盘子 
            P x = event[i]; 
    //        printf("x1=%d x2=%d
    ", x.x1, x.x2);
            x.w = 1; x.type = 0;
            c.push_back(x); x.type = 2;
            x.w = -1; x.x1 = event[i].x2;
            c.push_back(x);            
        }
        for(int i = l; i <= r; ++i)
        {//水果 
            c.push_back(q[i]);
        }
        sort(c.begin(), c.end(), cp1);
        for(int i = 0; i < c.size(); ++i)
        {
            if(c[i].type != 1) 
            {
    //            printf("x=%d y1=%d y2=%d
    ", c[i].x1, c[i].y1, c[i].y2);
                t.update(c[i].y1, c[i].y2, c[i].w);
            } 
            else 
            {
                int sum = t.query(c[i].y1);
    //            printf("sum=%d k=%d
    ", sum, c[i].k);
                if(sum >= c[i].k) lp.push_back(c[i]);
                else {c[i].k -= sum; rp.push_back(c[i]);}
            }
        }
        for(int i = 0; i < c.size(); ++i) if(c[i].type != 1)
            t.update(c[i].y1, c[i].y2, -c[i].w);
        for(int i = 0; i < lp.size(); ++i) q[l + i] = lp[i];
        for(int i = 0; i < rp.size(); ++i) q[l + lp.size() + i] = rp[i];
        int mid = l + lp.size() - 1;
        solve(l, mid, lb, mb); solve(mid + 1, r, mb + 1, rb);
    }
    int main()
    {
        freopen("fruit_hnoi2015.in", "r", stdin);
        freopen("fruit_hnoi2015.out", "w", stdout);
        scanf("%d%d%d",&n,&p,&m);
        for(int i = 1; i < n; ++i)
        {
            int u, v; scanf("%d%d",&u,&v);
            link(u, v); link(v, u);
        }
        memset(fa, -1, sizeof(fa));
        dfs(1, 0);
        for(int i = 1; i <= 22; ++i)
            for(int j = 1; j <= n; ++j) if(fa[i-1][j] != -1)
                fa[i][j] = fa[i-1][fa[i-1][j]];
        for(int i = 1; i <= p; ++i)
        {
            int u, v, w; scanf("%d%d%d", &u, &v, &w);
            int x = lca(u, v);
            if(dfn[u] > dfn[v]) swap(u, v);
            if(u != x) 
            {
                event[++cnt].x1 = dfn[u]; event[cnt].y1 = dfn[v];
                event[cnt].x2 = low[u]; event[cnt].y2 = low[v]; 
                event[cnt].w = w; 
            }
            else
            {
                int t = jump(v, dep[v] - dep[u] - 1);
                event[++cnt].x1 = 1; event[cnt].y1 = dfn[v];
                event[cnt].x2 = dfn[t] - 1; event[cnt].y2 = low[v];
                event[cnt].w = w;
                if(low[t] < n)
                {
                    event[++cnt].x1 = dfn[v]; event[cnt].y1 = low[t] + 1;
                    event[cnt].x2 = low[v]; event[cnt].y2 = n;
                    event[cnt].w = w; 
                }
            }
        }
        for(int i = 1; i <= m; ++i)
        {
            int u, v;
            scanf("%d%d%d", &u, &v, &q[i].k);
            if(dfn[u] > dfn[v]) swap(u, v);
            q[i].x1 = dfn[u]; q[i].y1 = dfn[v];
            q[i].id = i; q[i].type = 1;
        }
        sort(event + 1, event + cnt + 1, cp);
        solve(1, m, 1, cnt);
        for(int i = 1; i <= m; ++i) printf("%d
    ", ans[i]);
        fclose(stdin); fclose(stdout);
        return 0;
    }
    View Code
  • 相关阅读:
    yaf将错误输出打印在页面上
    yaf设置命名空间
    yaf学习资料
    在 Github 上找「好东西」的方法
    在linux命令行下执行php 程序
    linux shell脚本查找重复行/查找非重复行/去除重复行/重复行统计
    php数组函数分析--array_column
    php 去掉字符串的最后一个字符
    设置arc 的默认编辑器
    需要学习的技术
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6579675.html
Copyright © 2011-2022 走看看