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. python 爬虫的一些使用技巧

    1.最基本的抓站 import urllib2 content = urllib2.urlopen('http://XXXX').read() -2.使用代理服务器这在某些情况下比较有用,比如IP被封 ...

  2. ACM学习历程—51NOD 1770数数字(循环节)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1770 这是这次BSG白山极客挑战赛的A题.由于数字全部相同,乘上b必然会 ...

  3. 3145 code[VS]汉诺塔游戏--递归

    3145 汉诺塔游戏 题目描述 Description 汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题.在A,B,C三根柱子上,有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我 ...

  4. throw、try 和 catch

    try 语句允许我们定义在执行时进行错误测试的代码块. catch 语句允许我们定义当 try 代码块发生错误时,所执行的代码块. JavaScript 语句 try 和 catch 是成对出现的. ...

  5. django的多对一,一对一,多对多关系

    from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) a ...

  6. gogs docker 安装

     1.  gogs 镜像      docker pull gogs/gogs    2.  mysql    docker mysql    3.  本地数据卷配置 mkdir gogs & ...

  7. win10笔记本用Fiddler对手机App抓包

    移动客户端项目有时需要针对手机app进行抓包,这时一般有两种办法:直接下个手机抓包工具的app,在手机上抓:pc机上装上抓包工具,pc和手机连接同一个无线,在pc机上抓.第一种比较简单,但抓包工具自然 ...

  8. Scanner 的练习 。。。。依然不懂用法。。。苦恼

    package com.b; import java.util.Random; import java.util.Scanner; public class Core { public static ...

  9. Jenkins详细安装教程

    1.先下载msi文件 Jenkins下载链接: https://pan.baidu.com/s/1SACKNgW7OZrJoXMRDhsJxQ 提取码: 94b9 2.安装 解压后得到的是jenkin ...

  10. php代码中临时开启错误调试

    对php.ini 中参数的设置 也可用在php代码中完成. 调用:调用ini_set()函数 //开启php.ini中的display_errors指令 ini_set('display_errors ...