BZOJ4009 权限题

真的不想再写一遍了

大佬blog

假设有果实$(x, y)$,询问$(a, b)$,用$st_i$表示$i$的$dfs$序,用$ed_i$表示所有$i$的子树搜完的$dfs$序,那么果实对询问产生贡献只会有两种情况:

1、这个果实表示的区间是一条链

  不妨假设$dep_x < dep_y$,记$z$为$x$到$y$的树链上的从$x$向下走的第一个点,画个图可以发现$(a, b)$需要满足:

    $st_a \in [1, st_z - 1] \cup [ed_z + 1, n], \ st_b \in [st_y, ed_y]$,其中$(a, b)$可以互换。

2、这个果实表示的链是一条先向上再向下的纯正的树链

  仍然画个图发现$(a, b)$需要满足:$st_a \in [st_x, ed_x], \ st_b \in [st_y, ed_y]$, $(a, b)$仍然可以互换。

对于每一个询问$(a, b)$,只要看一看有多少果实满足上面两种选一种的条件,然后求个$k$小就好了。

发现这其实是一个在二维矩阵中动态加点求$k$小的问题,这时候$KDTree$就出现了,然而我不会……

考虑扫描线降维,一个矩阵根据$x$坐标拆成两条线然后排个序扫一扫,每一次根据询问的点的位置进行加入删除的调整然后求个$k$小就好了。

也就是说只要写一个支持在一条线上区间加区间减然后求$k$小的数据结构就好了,我们需要一个外层权值内层下标的线段树兹磁这个操作。

瓶颈在于树套树的$O(nlog^2n)$。

最好标记永久化一下。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 4e4 + ;
const int M = 3e7 + ;
const int Lg = ; int n, m, qn, lcnt = , mx = , num[N], tot = , head[N];
int dfsc = , st[N], ed[N], fa[N][Lg], dep[N], ans[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} struct Line {
int pos, x, y, v, type; inline Line (int nowPos = , int nowX = , int nowY = , int nowV = , int nowType = ) {
pos = nowPos, x = nowX, y = nowY, v = nowV, type = nowType;
} friend bool operator < (const Line &u, const Line &v) {
return u.pos < v.pos;
} } a[N << ]; inline void addLine(int l1, int r1, int l2, int r2, int v) {
a[++lcnt] = Line(l1, l2, r2, v, );
a[++lcnt] = Line(r1 + , l2, r2, v, -);
} struct Querys {
int x, y, k, id; friend bool operator < (const Querys &u, const Querys &v) {
return u.x < v.x;
} } q[N]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} void dfs(int x, int fat, int depth) {
fa[x][] = fat, dep[x] = depth, st[x] = ++dfsc;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
}
ed[x] = dfsc;
} inline int getPos(int x, int stp) {
int res = x;
for(int i = ; i >= ; i--)
if((stp >> i) & ) res = fa[res][i];
return res;
} namespace InSegT {
struct Node {
int lc, rc, sum;
} s[M]; int nodeCnt = ; #define lc s[p].lc
#define rc s[p].rc
#define sum(p) s[p].sum
#define mid ((l + r) >> 1) void modify(int &p, int l, int r, int x, int y, int v) {
if(!p) p = ++nodeCnt; if(x <= l && y >= r) {
sum(p) += v;
return;
} if(x <= mid) modify(lc, l, mid, x, y, v);
if(y > mid) modify(rc, mid + , r, x, y, v);
} int query(int p, int l, int r, int x) {
if(l == r) return sum(p);
int res = sum(p);
if(x <= mid) res += query(lc, l, mid, x);
else res += query(rc, mid + , r, x);
return res;
} #undef lc
#undef rc
#undef sum
} namespace OutSegT {
using namespace InSegT; #define lc p << 1
#define rc p << 1 | 1 int root[N << ]; void ins(int p, int l, int r, int x, int y, int pos, int type) {
modify(root[p], , n, x, y, type);
if(l == r) return; if(pos <= mid) ins(lc, l, mid, x, y, pos, type);
else ins(rc, mid + , r, x, y, pos, type);
} int getKth(int p, int l, int r, int x, int k) {
if(l == r) return l;
int now = query(root[lc], , n, x);
if(k <= now) return getKth(lc, l, mid, x, k);
else return getKth(rc, mid + , r, x, k - now);
} } using namespace OutSegT; int main() {
read(n), read(m), read(qn);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, , ); for(int x, y, v, i = ; i <= m; i++) {
read(x), read(y), read(v);
num[++mx] = v;
if(dep[x] > dep[y]) swap(x, y);
if(st[x] <= st[y] && ed[x] >= ed[y]) {
int z = getPos(y, dep[y] - dep[x] - );
if(ed[z] < n) {
addLine(st[y], ed[y], ed[z], n, v);
addLine(ed[z], n, st[y], ed[y], v);
}
if(st[z] > ) {
addLine(st[y], ed[y], , st[z] - , v);
addLine(, st[z] - , st[y], ed[y], v);
}
} else {
addLine(st[x], ed[x], st[y], ed[y], v);
addLine(st[y], ed[y], st[x], ed[x], v);
}
} sort(num + , num + mx + );
mx = unique(num + , num + + mx) - num - ;
for(int i = ; i <= lcnt; i++)
a[i].v = lower_bound(num + , num + mx + , a[i].v) - num; for(int i = ; i <= qn; i++) {
read(q[i].x), read(q[i].y), read(q[i].k);
q[i].x = st[q[i].x], q[i].y = st[q[i].y];
q[i].id = i;
} sort(q + , q + + qn);
sort(a + , a + + lcnt);
for(int j = , i = ; i <= qn; i++) {
for(; j <= lcnt && a[j].pos <= q[i].x; ++j)
ins(, , mx, a[j].x, a[j].y, a[j].v, a[j].type);
ans[q[i].id] = getKth(, , mx, q[i].y, q[i].k);
} for(int i = ; i <= qn; i++)
printf("%d\n", num[ans[i]]); return ;
}

Luogu 3242 [HNOI2015]接水果的更多相关文章

  1. luogu P3242 [HNOI2015]接水果

    传送门 其实这题难点在于处理路径包含关系 先求出树的dfn序,现在假设路径\(xy\)包含\(uv(dfn_x<dfn_y,dfn_u<dfn_v)\) 如果\(lca(u,v)!=u\) ...

  2. BZOJ4009: [HNOI2015]接水果

    4009: [HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black,  她 ...

  3. BZOJ 4009: [HNOI2015]接水果

    4009: [HNOI2015]接水果 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 636  Solved: 300[Submit][Status] ...

  4. [BZOJ4009][HNOI2015]接水果(整体二分)

    [HNOI2015]接水果 时间限制:60s      空间限制:512MB 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The b ...

  5. 洛谷 P3242 [HNOI2015]接水果 解题报告

    P3242 [HNOI2015]接水果 题目描述 风见幽香非常喜欢玩一个叫做 \(osu!\) 的游戏,其中她最喜欢玩的模式就是接水果.由于她已经\(DT\) \(FC\) 了\(\tt{The\ b ...

  6. [洛谷P3242] [HNOI2015]接水果

    洛谷题目链接:[HNOI2015]接水果 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, 她觉得这个游戏太简 ...

  7. 【BZOJ4009】[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组

    [BZOJ4009][HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, ...

  8. [HNOI2015]接水果[整体二分]

    [HNOI2015]接水果 给出一个树上路径集合\(S\) 多次询问\(x,y\)中的\(k\)小值 如果你问我数列上那么我会 树上的话 树上差分了吧直接?- 令 \(st_x<st_y\) 1 ...

  9. BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4009 https://www.luogu.org/problemnew/show/P3242 ht ...

随机推荐

  1. setContentHuggingPriority和setContentCompressionResistancePriority的使用

    当两个UILabel并排显示时,如何设置约束,让 leftLB 和 rightLB 正常显示就很重要了. 方案1:左右两个Label的宽度相同,则约束设置如下: //添加标题约束,左边的label [ ...

  2. 3 循环语句——《Swift3.0从入门到出家》

    3 循环语句 当一段代码被多次重复利用的使用我们就使用循环 swift提供了三种形式的循环语句 1.while 循环 2.repeat — while 循环 3.for — in 循环 while 循 ...

  3. php查询mysql时,报超出内存错误(select count(distinct))时

    学时服务器查询教练所带人数时,使用select count(distinct(u_STRNO))时报超出内存错误.后参考“mysqld-nt: Out of memory解决方法”http://jin ...

  4. android通过查询电话号码获取联系人信息

    // 取得Intent中的頭像 ivShowImage = (ImageView) findViewById(R.id.call_log_detail_contact_img); //通话电话号码获取 ...

  5. 关于android开发环境中sdk和adt更新到22.6之后多了appcompat_v7

    昨天我打开Eclipse更新了一下sdk和adt到22.6,更新一切都很顺利,很开心的样子,可以新建一个工程时发现多了一个appcompat_v7这个东西,一下子就把小编怔住了,后来才发现这是官方的一 ...

  6. sourcetree 分支的创建合并

    sourcetree 分支的创建合并,提交 https://blog.csdn.net/qq_34975710/article/details/74469068 sourcetree测试版本的配置忽略 ...

  7. [转载]amba_device使用分析

    什么是AMBA? ---AMBA是一个片内总线规范. ARM官网的介绍:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0 ...

  8. python开发mysql:表关系&单表简单查询

    一 一对多,多对一 1.1 建立多对一 ,一对多的关系需要注意 先建立被关联的表,被关联的字段必须保证时唯一的 在创建关联的表,关联的字段一定是可以重复的 1.2 示例: 出版社 多对一,多个老师可能 ...

  9. 第2章 深入分析java I/O的工作机制(下)

    2.6 设计模式解析之适配器模式 2.6.1 适配器模式的结构 把一个类的接口变换成一客户端能接受的另一个接口. Target(目标接口): 要转换的期待的接口. Adaptee(源角色):需要适配的 ...

  10. mysql索引原理与慢查询优化2

    七 正确使用索引 一 索引未命中 并不是说我们创建了索引就一定会加快查询速度,若想利用索引达到预想的提高查询速度的效果,我们在添加索引时,必须遵循以下问题 1 范围问题,或者说条件不明确,条件中出现这 ...