题目大意

\(n\)个点的树, 树上每一个点有一个宝石\(w_i\), 给出一个固定的数字不重复的序列\(p_i\)和一些询问\(u_i, v_i\), 对于每一个询问求出\(u_i\)到\(v_i\)的路径上, 按所给顺序\(p\)收集宝石的最多个数.

\(n,q <= 10^5\)

解题思路

考场上是一点没想到这个.做题还是少了.

我们考虑把颜色重编号, 使得颜色是在\(p\)中的顺序. 设这个新颜色为\(c_i\).

那么问题转化为在询问上找最长的连续正整数子序列.

我们把询问拆成两端 一段是\(u\)到\(lca\), 一段是\(lca\)到\(v\) (注意在代码中 要小心\(lca\)被算两次的细节, 下面的做法是把\(lca\)放到了第一部分处理)

对于前一部分, 我们尽量找出长的一段来, 设一个倍增数组\(f_{u,i}\)表示在\(u\)到根的路径上颜色为\(c_u+2^i\)的最深的节点所在的位置. 可以通过桶来辅助处理.

到了一个点 就往上跳到一个颜色最大的深度大于等于\(lca\)的节点 这能得到前半部分的答案.

然而后一部分不太好求. 某些神仙于是想到二分.

该预处理的差不多, 只是变成了\(c_u-2^i\)的颜色.

我们二分到一个答案, 往上跳对应的步数, 如果深度大于\(lca\)那么合法.

这么一讲貌似不难嘛 但是难想 也不好写.

时间复杂度\(O(n\log^2n)\)

#include <cstdio>
#include <vector>
#define L 17
#define M 50010
#define N 200010
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
#define fd(i, a, b) for(int i = (a); i >= (b); --i)
using namespace std;
inline int read()
{
int x = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return x;
}
int n, m, c, q, p[N], lc[N], dep[N], ord[N], ans[N], w[N], lastw[M], f[N][L + 5], g[N][L + 5];
int last[N], pre[N << 1], to[N << 1];
vector<int> s[N], t[N];
inline void add(int u, int v){static int tot = 0; to[++tot] = v, pre[tot] = last[u], last[u] = tot;}
void dfs1(int u)
{
dep[u] = dep[f[u][0]] + 1;
fo(i, 1, L) f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = last[u]; i; i = pre[i])
{
int v = to[i];
if(v == f[u][0]) return ;
f[v][0] = u; dfs1(v);
}
}
inline int lca(int x, int y)
{
if(dep[x] < dep[y]) return lca(y, x);
fd(i, L, 0)
if(dep[f[x][i]] >= dep[y])
x = f[x][i];
if(x == y) return x;
fd(i, L, 0) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
void dfs2(int u)
{
int tmp = lastw[w[u]];
lastw[w[u]] = dep[u];
g[dep[u]][0] = lastw[w[u] + 1];
fo(i, 1, L) g[dep[u]][i] = g[g[dep[u]][i - 1]][i - 1];
for(int i = 0, siz = s[u].size(); i < siz; ++i)
{
int qry = s[u][i], cur = lastw[1];
if(cur < dep[lc[qry]]) continue ;
++ans[qry];
fd(j, L, 0)
if(g[cur][j] >= dep[lc[qry]])
{
ans[qry] += (1 << j);
cur = g[cur][j];
}
}
for(int i = last[u]; i; i = pre[i])
{
int v = to[i];
if(v != f[u][0]) dfs2(v);
}
lastw[w[u]] = tmp;
}
void dfs3(int u)
{
int tmp = lastw[w[u]];
lastw[w[u]] = dep[u];
g[dep[u]][0] = lastw[w[u] - 1];
fo(i, 1, L) g[dep[u]][i] = g[g[dep[u]][i - 1]][i - 1];
for(int i = 0, siz = t[u].size(); i < siz; ++i)
{
int qry = t[u][i];
int l = ans[qry] + 1, r = c, res = ans[qry];
while(l <= r)
{
int mid = (l + r) >> 1;
int cur = lastw[mid], cnt = mid - ans[qry] - 1;
fd(j, L, 0) ((1 << j) & cnt) && (cur = g[cur][j]);
cur > dep[lc[qry]] ? (l = (res = mid) + 1) : (r = mid - 1);
}
ans[qry] = res;
}
for(int i = last[u]; i; i = pre[i])
{
int v = to[i];
if(v != f[u][0]) dfs3(v);
}
lastw[w[u]] = tmp;
}
int main()
{
freopen("gem.in", "r", stdin);
freopen("gem.out", "w", stdout);
int u, v;
n = read(), m = read(), c = read();
fo(i, 1, c) p[i] = read(), ord[p[i]] = i;
fo(i, 1, n) w[i] = ord[read()];
fo(i, 2, n) u = read(), v = read(), add(u, v), add(v, u);
dfs1(1);
q = read();
fo(i, 1, q) u = read(), v = read(), lc[i] = lca(u, v), s[u].push_back(i), t[v].push_back(i);
dfs2(1);
dfs3(1);
fo(i, 1, q) printf("%d\n", ans[i]);
return 0;
}

[GDOI2021 Day2T1] 宝石的更多相关文章

  1. BZOJ1190[HNOI2007]梦幻岛宝石

    Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值.数据范围:N<=100;W<=2^30, ...

  2. BZOJ-1625 宝石手镯 01背包(傻逼题)

    傻逼题,懒得打,复制蛋蛋的.. 1625: [Usaco2007 Dec]宝石手镯 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1076 Solved: ...

  3. BZOJ_1625_ [Usaco2007_Dec]_宝石手镯_(01背包)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1625 01背包裸题. p.s.随便点开一道就是水题... 分析 ... #include &l ...

  4. BZOJ 1625: [Usaco2007 Dec]宝石手镯( dp )

    最裸的01背包.... --------------------------------------------------------------------- #include<cstdio ...

  5. PHP SPL他们留下的宝石

    Rafael Dohms 上面的篇文章 让我为之惊艳,忍不住就翻译了下来,同一时候补充了部分内容. SPL,PHP 标准库(Standard PHP Library) ,此从 PHP 5.0 起内置的 ...

  6. Linux:闪光的宝石,智慧 (在)

    Linux:闪光的宝石,智慧的结晶(上) 老实说,这十几天以来.因为我违反了"家规",又被断网处罚(拔掉网线).没收手机与老年证(不许出家门). 因此.我平日里仅仅能面对一篇文章& ...

  7. Linux:闪光的宝石,智慧(下一个)

    2005年4月7日.Linus Torvalds公布了一款新型通用工具软件包,叫做"Git"(the Git source code management system).&quo ...

  8. [Usaco2007 Dec]宝石手镯[01背包][水]

    Description 贝茜在珠宝店闲逛时,买到了一个中意的手镯.很自然地,她想从她收集的 N(1 <= N <= 3,402)块宝石中选出最好的那些镶在手镯上.对于第i块宝石,它的重量为 ...

  9. 1625: [Usaco2007 Dec]宝石手镯

    1625: [Usaco2007 Dec]宝石手镯 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 919  Solved: 618 [Submit][S ...

随机推荐

  1. shell脚本计算Linux网卡流量

    本文介绍了计算linux网卡流量的一个shell脚本,一个通过固定间隔时间获取ifconfig eth0 的字节值而计算出网卡流量的方法,有需要的朋友参考下. 使用shell脚本计算Linux网卡流量 ...

  2. 基于jar的Spring Boot工程

    一.Spring Boot简介 Spring Boot是由Pivotal[ˈpɪvətl]团队(一家做大数据的公司)提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架 ...

  3. 使用JSP实现输出

    一.在JSP页面添加java代码,实现输出,java代码写在<% %>中. 代码示例1: <body> <!-- HTML注释 --> <%-- JSP注释 ...

  4. C#获取Windows10屏幕的缩放比例

    现在1920x1080以上分辨率的高分屏电脑渐渐普及了.我们会在Windows的显示设置里看到缩放比例的设置.在Windows桌面客户端的开发中,有时会想要精确计算窗口的面积或位置.然而在默认情况下, ...

  5. Android 内存泄漏检测工具 LeakCanary(Kotlin版)的实现原理

    LeakCanary 是一个简单方便的内存泄漏检测框架,做 android 的同学基本都收到过 LeakCanary 检测出来的内存泄漏.目前 LeakCanary 最新版本为 2.7 版本,并且采用 ...

  6. shell脚本 系统状态信息查看

    一.简介 源码地址 日期:2018/6/23 介绍:显示简单的系统信息 效果图: 二.使用 适用:centos6+,ubuntu12+ 语言:中文 注意:无 下载 wget https://raw.g ...

  7. 车载以太网第二弹|测试之实锤-1000BASE-T1物理层PMA测试实践

    背景 100BASE-T1方兴未艾,国内外OEM量产车型纷至沓来:为了满足高带宽的应用场景需求(如图像.雷达等数据传输),1000BASE-T1将至已至,如大众MEB平台采用1000BASE-T1总线 ...

  8. 【LeetCode】1221. Split a String in Balanced Strings 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 统计 日期 题目地址:https://leetcode ...

  9. 【LeetCode】775. Global and Local Inversions 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/global-a ...

  10. LeetCode1238循环码排列

    题目 给你两个整数 n 和 start.你的任务是返回任意 (0,1,2,,...,2n-1) 的排列 p,并且满足: p[0] = start p[i] 和 p[i+1] 的二进制表示形式只有一位不 ...