zoukankan      html  css  js  c++  java
  • [HNOI 2015]接水果

    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。

    题解

    (部分内容来自thy_asdf

    我们考虑如果这个题不出在树上,而在序列上,很容易想到用$cdq$来解决。

    我们想办法将树拍成一条链,通常办法是$dfs$序(其实树剖的实质也是$dfs$序),再试图找到他们之间的$dfs$序关系。

    对于一条路径的子路径,在有根树上只有两种情况。我们分别考虑两种情况(记号说明:$dfn_u$表示$u$的$dfs$序,$last_u$表示以$u$为根的子树中$dfs$序最大的值):

    1. 子路径经过整条路径的$lca$:

    如上图所示,假设子路径$u<->v$在路径$a<->b$上。显然$a,b$分别在以$u,v$为根的子树中。

    不妨设$dfn_u<=dfn_v$,$dfn_a<=dfn_b$,由$dfs$序的性质,显然存在不等式:$dfn_u<=dfn_a<=last_u$,$dfn_v<=dfn_b<=last_v$。

    2. 子路径不经过整条路径的$lca$:

    我们记节点$u$在路径$u<->v$上的儿子是$w$。

    同样的,容易发现,路径$a<->b$若包含$u<->v$肯定需要$a$或$b$其中一个是在以$v$为根的子树中。不妨假设这个点是$a$。

    那么$b$应满足:不在以$w$为根的子树中即可。

    显然就有$dfn_v<=dfn_a<=last_v$,$1<=dfn_b<=dfn_w-1 cup last_w+1<=dfn_b<=n$。

    那么现在题目就转化成了不等式之间的关系,考虑$cdq$,我们需要解决的问题就是一个实数对$(dfn_a,dfn_b)$满足不等式组的个数。

    继续转化,将需要同时满足的两个不等式抽象成二位空间内的一个矩形,只要点$(dfn_a,dfn_b)$在某个矩形内,就能满足这个不等式组。

    现在,整个题目就是覆盖一个点的矩形中权值第$k$小的权值是多少。

    将矩形按权值从小到大排序,用扫描线的思想,树状数组区间修改即可。

      1 //It is made by Awson on 2017.12.30
      2 #include <map>
      3 #include <set>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <vector>
      9 #include <cstdio>
     10 #include <string>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define LD long double
     17 #define Max(a, b) ((a) > (b) ? (a) : (b))
     18 #define Min(a, b) ((a) < (b) ? (a) : (b))
     19 #define lowbit(x) ((x)&(-(x)))
     20 using namespace std;
     21 const int N = 80000;
     22 
     23 int n, p, q, ans[N+5];
     24 int st[N+5], ed[N+5];
     25 namespace LCA {
     26     struct tt {
     27     int to, next;
     28     }edge[(N<<1)+5];
     29     int path[N+5], tot, u, v, dfn;
     30     int top[N+5], size[N+5], son[N+5], fa[N+5], dep[N+5];
     31     void add(int u, int v) {
     32     edge[++tot].to = v;
     33     edge[tot].next = path[u];
     34     path[u] = tot;
     35     }
     36     void dfs1(int u, int father, int depth) {
     37     fa[u] = father, size[u] = 1, dep[u] = depth;
     38     for (int i = path[u]; i; i = edge[i].next)
     39         if (edge[i].to != father) {
     40         dfs1(edge[i].to, u, depth+1);
     41         size[u] += size[edge[i].to];
     42         if (size[edge[i].to] >= size[son[u]]) son[u] = edge[i].to;
     43         }
     44     }
     45     void dfs2(int u, int tp) {
     46     top[u] = tp; st[u] = ++dfn;
     47     if (son[u]) dfs2(son[u], tp);
     48     for (int i = path[u]; i; i = edge[i].next)
     49         if (edge[i].to != fa[u] && edge[i].to != son[u])
     50         dfs2(edge[i].to, edge[i].to);
     51     ed[u] = dfn;
     52     }
     53     int get_son(int u, int v) {
     54     int last = 0;
     55     while (top[u] != top[v]) {
     56         last = top[v];
     57         v = fa[last];
     58     }
     59     return u == v ? last : son[u];
     60     }
     61     int query(int u, int v) {
     62     while (top[u] != top[v]) {
     63         if (dep[top[u]] < dep[top[v]]) swap(u, v);
     64         u = fa[top[u]];
     65     }
     66     return dep[u] < dep[v] ? u : v;
     67     }
     68     void main() {
     69     for (int i = 1; i < n; i++) {
     70         scanf("%d%d", &u, &v);
     71         add(u, v), add(v, u);
     72     }
     73     dfs1(1, 0, 1); dfs2(1, 1);
     74     }
     75 }
     76 namespace CDQ {
     77     struct tt {
     78     int x1, x2, y1, y2, k;
     79     tt() {
     80     }
     81     tt(int _x1, int _x2, int _y1, int _y2, int _k) {
     82         x1 = _x1, y1 = _y1, x2 = _x2, y2 = _y2, k = _k;
     83     }
     84     bool operator < (const tt &b) const {
     85         return k < b.k;
     86     }
     87     }opt[N+5];
     88     struct ss {
     89     int x, y, k, id;
     90     ss() {
     91     }
     92     ss(int _x, int _y, int _k, int _id) {
     93         x = _x, y = _y, k = _k, id = _id;
     94     }
     95     bool operator < (const ss &b) const {
     96         return x < b.x;
     97     }
     98     }query[N+5], qu1[N+5], qu2[N+5];
     99     int u, v, k, P;
    100     struct ttt {
    101     int x, y, val;
    102     ttt() {
    103     }
    104     ttt(int _x, int _y, int _val) {
    105         x = _x, y = _y, val = _val;
    106     }
    107     bool operator < (const ttt &b) const {
    108         return x < b.x;
    109     }
    110     }doit[(N<<1)+5];
    111     struct bit_tree {
    112     int c[N+5];
    113     void add(int x, int val) {
    114         for (; x <= n; x += lowbit(x)) c[x] += val;
    115     }
    116     int count(int x) {
    117         int ans = 0;
    118         for (; x; x -= lowbit(x)) ans += c[x];
    119         return ans;
    120     }
    121     }T;
    122     void solve(int ql, int qr, int pl, int pr) {
    123      if (pl == pr) {
    124         for (int i = ql; i <= qr; i++) ans[query[i].id] = opt[pl].k;
    125         return;
    126     }
    127     int mid = (pl+pr)>>1, cnt = 0, pos = 0, q1 = 0, q2 = 0;
    128     for (int i = pl; i <= mid; i++) {
    129         doit[++cnt] = ttt(opt[i].x1, opt[i].y1, 1);
    130         doit[++cnt] = ttt(opt[i].x1, opt[i].y2+1, -1);
    131         doit[++cnt] = ttt(opt[i].x2+1, opt[i].y1, -1);
    132         doit[++cnt] = ttt(opt[i].x2+1, opt[i].y2+1, 1);
    133     }
    134     sort(doit+1, doit+1+cnt);
    135     for (int i = ql; i <= qr; i++) {
    136         while (pos < cnt && doit[pos+1].x <= query[i].x) pos++, T.add(doit[pos].y, doit[pos].val);
    137         int tmp = T.count(query[i].y);
    138          if (query[i].k <= tmp) qu1[++q1] = query[i];
    139         else query[i].k -= tmp, qu2[++q2] = query[i];
    140     }
    141     while (pos < cnt) pos++, T.add(doit[pos].y, doit[pos].val);
    142     for (int i = 1; i <= q1; i++) query[i+ql-1] = qu1[i];
    143     for (int i = 1; i <= q2; i++) query[i+q1+ql-1] = qu2[i];
    144     if (q1) solve(ql, ql+q1-1, pl, mid);
    145     if (q2) solve(ql+q1, qr, mid+1, pr);
    146     }
    147     void main() {
    148     for (int i = 1; i <= p; i++) {
    149         scanf("%d%d%d", &u, &v, &k);
    150         if (st[u] > st[v]) swap(u, v);
    151         int w = LCA::query(u, v);
    152         if (u == w) {
    153         w = LCA::get_son(u, v);
    154         if (st[w] > 1) opt[++P] = tt(1, st[w]-1, st[v], ed[v], k);
    155         if (ed[w] < n) opt[++P] = tt(st[v], ed[v], ed[w]+1, n, k);
    156         }else opt[++P] = tt(st[u], ed[u], st[v], ed[v], k);
    157     }
    158     p = P;
    159     for (int i = 1; i <= q; i++) {
    160         scanf("%d%d%d", &u, &v, &k);
    161         if (st[u] > st[v]) swap(u, v);
    162         query[i] = ss(st[u], st[v], k, i);
    163     }
    164     sort(opt+1, opt+1+p); sort(query+1, query+1+q);
    165         solve(1, q, 1, p);
    166     }
    167 }
    168 
    169 void work() {
    170     scanf("%d%d%d", &n, &p, &q);
    171     LCA::main();
    172     CDQ::main();
    173     for (int i = 1; i <= q; i++) printf("%d
    ", ans[i]);
    174 }
    175 int main() {
    176     work();
    177     return 0;
    178 }
  • 相关阅读:
    1066 Bash 游戏
    1070 Bash 游戏 V4
    codevs 2928 你缺什么
    分块、线段树练习
    Father Christmas flymouse
    codevs 2494 Vani和Cl2捉迷藏
    codevs 2144 砝码称重2
    国王游戏
    codevs 1664 清凉冷水
    2015ACM/ICPC亚洲区沈阳站 Pagodas
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8150418.html
Copyright © 2011-2022 走看看