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\n", 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\n", 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\n", 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\n", ans[i]);
    fclose(stdin); fclose(stdout);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/19992147orz/p/6579675.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值