相似序列
题目大意
给你一个数组,多次询问,每次问你两个长度相等的子区间,问你把这两个区间排序之后,是否至多只有一个位置的数不同。
思路
看到这些不难想到用个什么数据结构维护出一个区间的每个数的出现次数。
然后把每个数的出现次数用个哈希搞出来来快速判断是否相同。
然后看到区间,每个值,不难想到主席树。
然后接着考虑如何判断,首先如果直接哈希值相同就可以。
那如果不相同,我们可以通过一个小小的二分找到它第一个有不同出现次数的数。
然后我们考虑一下如果只有一个位置不同那会怎么样。
首先就只会有两个数值的出现次数不同,接着就是这两个数值中间是不能掺杂其它数的。
那我们不妨把接下来的一个有出现的数找到,那后面的数肯定就是要全部匹配上了。
然后你还发现,当然是两个数值的出现次数不同的大小只能是 1,而且要一个多 1,一个少 1。
后面的条件换句话说,就是要这两个数的出现次数和是一样的。
然后就按着上面的判断一下就好了。
代码
#include<cstdio>
#define mo 131
#define ll unsigned long long
using namespace std;
int n, q, l1, l2, r1, r2, a[100005];
ll di[100005];
int Abs(int x) {
return x < 0 ? -x : x;
}
struct XD_tree {
int rt[100005], tot;
int ls[100005 << 6], rs[100005 << 6];
ll val[100005 << 6];
void up(int now, int l, int r) {
int mid = (l + r) >> 1;
val[now] = val[ls[now]] * di[r - mid] + val[rs[now]];
}
int copy(int x) {
int now = ++tot;
ls[now] = ls[x]; rs[now] = rs[x];
val[now] = val[x];
return now;
}
int insert(int now, int l, int r, int pl) {
now = copy(now);
if (l == r) {
val[now]++;
return now;
}
int mid = (l + r) >> 1;
if (pl <= mid) ls[now] = insert(ls[now], l, mid, pl);
else rs[now] = insert(rs[now], mid + 1, r, pl);
up(now, l, r);
return now;
}
ll query(int now, int l, int r, int L, int R) {
if (!now || L > R) return 0;
if (L <= l && r <= R) {
return val[now];
}
int mid = (l + r) >> 1;
if (L > mid) return query(rs[now], mid + 1, r, L, R);
if (mid >= R) return query(ls[now], l, mid, L, R);
ll x = query(ls[now], l, mid, L, R), y = query(rs[now], mid + 1, r, L, R);
return x * di[R - mid] + y;
}
ll get_va_(int l, int r, int vl, int vr) {
if (vl > vr) return 0;
return query(rt[r], 1, 100000, vl, vr) - query(rt[l - 1], 1, 100000, vl, vr);
}
}T;
int get_L(int l1, int r1, int l2, int r2) {
int l = 1, r = 100000, ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (T.get_va_(l1, r1, 1, mid) != T.get_va_(l2, r2, 1, mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
return ans;
}
int get_nxt(int l1, int r1, int l2, int r2, int X) {
int l = X + 1, r = 100000, ans = X;
while (l <= r) {
int mid = (l + r) >> 1;
if (T.get_va_(l1, r1, X + 1, mid) || T.get_va_(l2, r2, X + 1, mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
return ans;
}
int main() {
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
di[0] = mo;
for (int i = 1; i <= 100000; i++)
di[i] = di[i - 1] * mo;
for (int i = 1; i <= n; i++) {
T.rt[i] = T.insert(T.rt[i - 1], 1, 100000, a[i]);
}
while (q--) {
scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
if (T.get_va_(l1, r1, 1, 100000) == T.get_va_(l2, r2, 1, 100000)) {
printf("YES\n");
}
else {
ll X = get_L(l1, r1, l2, r2);
ll Y = get_nxt(l1, r1, l2, r2, X);
int x1 = T.get_va_(l1, r1, X, X), y1 = T.get_va_(l2, r2, X, X);
int x2 = T.get_va_(l1, r1, Y, Y), y2 = T.get_va_(l2, r2, Y, Y);
if (x1 + x2 == y1 + y2 && Abs(x1 - y1) <= 1 && T.get_va_(l1, r1, Y + 1, 100000) == T.get_va_(l2, r2, Y + 1, 100000)) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现