CF1080F Katya and Segments Sets

本文介绍了一种使用主席树和线段树解决特定区间查询问题的方法。通过线段排序和主席树版本控制,实现了对指定条件的高效判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:洛谷

题目描述:【看翻译】


这种强制在线的方法可真是奇妙。

主席树可真是奇妙。

我们用主席树的版本维护$x\leq l$的限制,用线段树维护$[a,b]$的限制,用节点的值来维护$r\leq y$的限制。

详细地说,就是先将线段排序($l$为第一关键字,$r$为第二关键字),然后倒序所属集合作为位置,右端点作为值插入主席树。

主席树的第$i$个版本维护的是排序后,后面$k-i+1$个线段的线段树。

因为它要求集合里面有一个满足就可以,所以同一个位置的右端点取最小值

因为它要求$[a,b]$的集合都要满足,所以线段树维护区间最大值

每次查询的时候,找到左端点$\geq x$的最靠前的线段,设为第$i$个,则在第$i$个版本中,看$[a,b]$的最大值是否$\leq y$,如果是就是yes,否则就是no。

 1 #include<bits/stdc++.h>
 2 #define Rint register int
 3 using namespace std;
 4 const int N = 300003, INF = 0x3f3f3f3f;
 5 struct Seg {
 6     int l, r, p;
 7     inline bool operator < (const Seg &o) const {return l < o.l || l == o.l && r < o.r;}
 8 } a[N];
 9 int n, m, k, cnt, root[N], seg[N << 5], ls[N << 5], rs[N << 5];
10 inline void pushup(int x){
11     seg[x] = max(seg[ls[x]], seg[rs[x]]);
12 }
13 inline void build(int &x, int L, int R){
14     seg[x = ++ cnt] = INF;
15     if(L == R) return;
16     int mid = L + R >> 1;
17     build(ls[x], L, mid);
18     build(rs[x], mid + 1, R);
19 }
20 inline void change(int &nx, int ox, int L, int R, int pos, int val){
21     seg[nx = ++ cnt] = seg[ox];
22     ls[nx] = ls[ox]; rs[nx] = rs[ox];
23     if(L == R){
24         seg[nx] = min(seg[nx], val);
25         return;
26     }
27     int mid = L + R >> 1;
28     if(pos <= mid) change(ls[nx], ls[ox], L, mid, pos, val);
29     else change(rs[nx], rs[ox], mid + 1, R, pos, val);
30     pushup(nx);
31 }
32 inline int query(int x, int L, int R, int l, int r){
33     if(l <= L && R <= r) return seg[x];
34     int mid = L + R >> 1, ans = 0;
35     if(l <= mid) ans = max(ans, query(ls[x], L, mid, l, r));
36     if(mid < r) ans = max(ans, query(rs[x], mid + 1, R, l, r));
37     return ans;
38 }
39 int main(){
40     scanf("%d%d%d", &n, &m, &k);
41     for(Rint i = 1;i <= k;i ++)
42         scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].p);
43     sort(a + 1, a + k + 1);
44     build(root[k + 1], 1, n);
45     for(Rint i = k;i;i --)
46         change(root[i], root[i + 1], 1, n, a[i].p, a[i].r);
47     a[k + 1].l = INF; 
48     while(m --){
49         int A, B, X, Y;
50         scanf("%d%d%d%d", &A, &B, &X, &Y);
51         int ans = -1, mid, left = 1, right = k + 1;
52         while(left <= right){
53             mid = left + right >> 1;
54             if(a[mid].l >= X) ans = mid, right = mid - 1;
55             else left = mid + 1;
56         }
57         puts(query(root[ans], 1, n, A, B) <= Y ? "yes" : "no");
58         fflush(stdout);
59     }
60 }
View Code

 

转载于:https://www.cnblogs.com/AThousandMoons/p/ntfakgdoi.html

内容概要:本文档主要展示了C语言中关于字符串处理、指针操作以及动态内存分配的相关代码示例。首先介绍了如何实现键值对(“key=value”)字符串的解析,包括去除多余空格和根据键获取对应值的功能,并提供了相应的测试用例。接着演示了从给定字符串中分离出奇偶位置字符的方法,并将结果分别存储到两个不同的缓冲区中。此外,还探讨了常量(const)修饰符在变量和指针中的应用规则,解释了不同类型指针的区别及其使用场景。最后,详细讲解了如何动态分配二维字符数组,并实现了对这类数组的排序与释放操作。 适合人群:具有C语言基础的程序员或计算机科学相关专业的学生,尤其是那些希望深入理解字符串处理、指针操作以及动态内存管理机制的学习者。 使用场景及目标:①掌握如何高效地解析键值对字符串并去除其中的空白字符;②学会编写能够正确处理奇偶索引字符的函数;③理解const修饰符的作用范围及其对程序逻辑的影响;④熟悉动态分配二维字符数组的技术,并能对其进行有效的排序和清理。 阅读建议:由于本资源涉及较多底层概念和技术细节,建议读者先复习C语言基础知识,特别是指针和内存管理部分。在学习过程中,可以尝试动手编写类似的代码片段,以便更好地理解和掌握文中所介绍的各种技巧。同时,注意观察代码注释,它们对于理解复杂逻辑非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值