Segments

1078. Segments

Time limit: 1.0 second
Memory limit: 64 MB
A number of segments are lying on a line. Every segment is given with the coordinates of its endpoints. Segments are numbered from 1 to N (0 < N < 500). We assume, that one segment is inside another, if the two segments are different, the first one is fully contained in the second one, and their endpoints do not coincide. Write a program, which finds the numbers of the segments in the longest sequence of segments which are contained in. In the sequence, every segment except the last is inside the next segment in the sequence.

Input

The first line contains one integer N. Next, there are N lines, with two integers on every line, which are the coordinates of the left and the right endpoints of the corresponding segment. These coordinates are integers in the interval [–10000, 10000]. We assume that, the given segments are numbered according to their place in the input.

Output

The first line must contain one integer, equal to the number of segments in the found sequence. The following line must contain the numbers of the segments in this sequence. These numbers must be outputted, in the order in which the segments' lengths increase, starting from the smallest. If there are more than one output sequences, write any of them.

Sample

input output
4
-2 2
-1 1
-3 3
4 5
3
2 1 3


/***
     设DP[i]为到第i个区间时,最大能够有多少个区间满足关系.
     首先,我们需要将原来的区间按照右端点排序,如果不排,
          比划一下:
     n=4
     区间如下:
     1*************
     2   ********
     3  ***
     4 ******
     如上:dp[1]=1,dp[2]=1,dp[3]=1,dp[4]=1. = =!实际上,dp[1]=3,dp[3]=1,dp[4]=2
     
     在为第一组找最大区间数量时,被它包含的区间没有更新,因此,没办法找到最大值.....
     所以,排序后:
     1  ***
     2 ******
     3   ********
     4*************
     如果,大区间能包含小区间,那小区间现在一定在大区间前面,
     那我们只需要按照找最长上升子序列对每个区间的左端点进行dp.......
     方程见代码:
***/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
#define maxn 5005

struct  Segment
{
    int l,r;
    int len;//这个没用= =!
    int id;
} s[maxn];

int n;
int dp[maxn];
int pre[maxn];//pre[x]表示,x直接包含的那个区间的下标,是排序后的

bool cmp(Segment a,Segment b)//按右端点排序
{
    return a.r<b.r;
}
void read()
{
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].id=i+1;
        s[i].len=s[i].r-s[i].l;
    }
    sort(s,s+n,cmp);//排序
}

int DP()
{
    memset(pre,-1,sizeof(pre));//初始化为-1
    for(int i=0; i<n; i++)
        dp[i]=1;
    for(int i=0; i<n; i++)
        for(int j=0; j<i; j++)
            if(s[i].l<s[j].l&&s[i].r>s[j].r)//题目要求的是被包含的是与包含者左右区间端点不相同,在这点我WA了一次
                if(dp[j]+1>dp[i])//求最大包含量
                {
                    dp[i]=dp[j]+1;
                    pre[i]=j;//标记前缀
                }
    int max=0;
    for(int i=0; i<n; i++)
        if(dp[i]>dp[max])
            max=i;
    return max;//返还最大dp的下标
}

void print(int x)//用最大dp的下标寻找序列
{
    if(x==-1)
    return ;
    print(pre[x]);//这里不用考虑长度,因为,按端点排序后,一旦a区间包含b区间,b区间的长度一定小于a区间
    printf("%d ",s[x].id);
}

int main()
{
    read();
    int x=DP();
    printf("%d\n",dp[x]);
    print(x);
    printf("\n");
    return 0;
}


<think>我们正在讨论编程或数据结构中的“段”(segments)概念。根据用户的问题,我们需要解释“segments”在编程或数据结构中的含义和应用。在计算机科学中,“段”(segment)可以指不同的概念,具体取决于上下文。以下是几个常见的含义:1.**内存段(MemorySegments)**:在计算机体系结构中,内存被划分为不同的段,例如代码段(textsegment)、数据段(datasegment)、BSS段(bsssegment)、堆(heap)和栈(stack)。这种分段是为了更有效地管理内存和提供内存保护。-**代码段**:存放可执行指令。-**数据段**:存放已初始化的全局变量和静态变量。-**BSS段**:存放未初始化的全局变量和静态变量。-**堆段**:动态分配的内存区域。-**栈段**:用于函数调用和局部变量。引用[2]中提到:“主机可访问区域,存放应用程序数据结构和程序数据。”这里的数据结构可能存放在数据段或堆段中。2.**分段存储管理(SegmentationinMemoryManagement)**:在操作系统中,分段是一种内存管理技术,其中每个段是一个逻辑单元(如程序的一个函数、一个数组等),可以独立地分配到内存的不同区域。每个段有自己的基址和长度,通过段表进行映射。3.**数据结构中的段(SegmentsinDataStructures)**:在某些数据结构中,段被用来表示数据的一个连续部分。例如:-**线段树(SegmentTree)**:一种二叉树数据结构,用于高效地处理区间查询(如区间最小值、区间和等)。每个节点代表一个区间(段)。-**分段数组(SegmentedArrays)**:将大数组分成多个小段(块)以优化性能(例如在缓存中使用)。4.**网络通信中的段(SegmentsinNetworking)**:在TCP/IP协议中,传输层的TCP协议将数据分割成多个段(segments)进行传输。5.**文件系统中的段(SegmentsinFileSystems)**:一些文件系统(如日志结构文件系统)将数据写入到固定大小的段中。由于用户的问题是关于编程或数据结构的,我们将重点放在内存段和线段树这两种常见的意义上。###内存段在程序执行时,内存被划分为多个段,每个段有特定的用途。例如,在C语言程序中:-代码段(.text):存储机器指令。-数据段(.data):存储已初始化的全局变量和静态变量。-BSS段(.bss):存储未初始化的全局变量和静态变量(程序加载时初始化为0)。-堆(heap):动态分配的内存(如`malloc`分配的内存)。-栈(stack):用于函数调用,存储局部变量、函数参数等。这种分段使得程序的内存管理更加有序和安全。###线段树(SegmentTree)线段树是一种非常重要的数据结构,用于解决区间查询问题。它可以在$O(\logn)$时间内完成区间查询(如区间最小值、区间和等)和单点更新,如果支持区间更新则需要惰性传播(lazypropagation)。线段树的基本思想是将一个区间划分成一些子区间(段),每个节点代表一个区间。线段树是一棵二叉树,根节点代表整个区间,每个叶子节点代表一个元素,内部节点代表区间的合并。例如,对于数组$A=[1,3,5,7,9,11]$,构建的线段树(求和)如下:```[0:5]=>36/\[0:2]=>9[3:5]=>27/\/\[0:1]=>4[2:2]=>5[3:4]=>16[5:5]=>11/\/\[0:0]=1[1:1]=3[3:3]=7[4:4]=9```每个节点存储对应区间的和。查询区间[1:4]的和,即3+5+7+9=24,可以通过合并节点[1:1](3)、[2:2](5)和[3:4](16)得到。线段树的构建、查询和更新操作都可以用递归实现。####线段树的代码示例(求和)以下是一个线段树的简单实现(支持区间求和查询和单点更新):```pythonclassSegmentTree:def__init__(self,arr):self.n=len(arr)self.size=4*self.n#线段树数组的大小通常为原数组的4倍self.tree=[0]*self.sizeself.arr=arrself._build(0,0,self.n-1)def_build(self,idx,l,r):ifl==r:self.tree[idx]=self.arr[l]returnmid=(l+r)//2self._build(2*idx+1,l,mid)self._build(2*idx+2,mid+1,r)self.tree[idx]=self.tree[2*idx+1]+self.tree[2*idx+2]defquery(self,ql,qr,idx=0,l=0,r=None):ifrisNone:r=self.n-1#查询区间[ql,qr]与当前节点区间[l,r]无重叠ifqr<lorr<ql:return0#当前节点区间完全包含在查询区间内ifql<=landr<=qr:returnself.tree[idx]mid=(l+r)//2left_sum=self.query(ql,qr,2*idx+1,l,mid)right_sum=self.query(ql,qr,2*idx+2,mid+1,r)returnleft_sum+right_sumdefupdate(self,pos,val,idx=0,l=0,r=None):ifrisNone:r=self.n-1ifl==r:self.arr[pos]=valself.tree[idx]=valreturnmid=(l+r)//2ifpos<=mid:self.update(pos,val,2*idx+1,l,mid)else:self.update(pos,val,2*idx+2,mid+1,r)self.tree[idx]=self.tree[2*idx+1]+self.tree[2*idx+2]#示例使用arr=[1,3,5,7,9,11]st=SegmentTree(arr)print(st.query(1,4))#输出24,因为3+5+7+9=24st.update(2,10)#将位置2的元素从5更新为10print(st.query(1,4))#输出29,因为3+10+7+9=29```###总结在编程和数据结构中,“段”(segments)的概念可以出现在多个层面:-内存管理中的内存段,用于组织程序的内存布局。-数据结构中的线段树,用于高效区间查询。-其他领域如网络和文件系统中的段。用户可以根据具体上下文选择关注的方向。例如,如果用户关注内存组织,则内存段是重点;如果关注区间查询问题,则线段树是重点。§§相关问题§§1.内存分段和分页有什么区别?2.线段树和树状数组(FenwickTree)有什么异同?3.线段树如何支持区间更新(使用惰性传播)?4.在哪些实际应用场景中会使用到线段树?</think>在编程和数据结构中,“段”(segments)通常指内存分段或特定数据结构中的连续区间概念。以下是主要应用场景和技术解析: ### 一、内存分段(Memory Segmentation) 操作系统和硬件层面将内存划分为逻辑段,用于隔离程序的不同部分: 1. **代码段(Text Segment)** 存储可执行指令(只读),如函数代码。 *示例:* 程序中的`main()`函数指令 2. **数据段(Data Segment)** - 已初始化全局变量(`.data`) - 未初始化全局变量(`.bss`) *引用示例:* “主机可访问区域,存放应用程序数据结构和程序数据”[^2] 3. **堆段(Heap Segment)** 动态分配的内存(如`malloc()`/`new`创建的对象) 4. **栈段(Stack Segment)** 存储函数调用栈、局部变量(自动管理) ```c int global_var; // 存储在.bss段 int init_var = 10; // 存储在.data段 int main() { // 代码段 int local_var; // 栈段 int* ptr = malloc(sizeof(int)); // 堆段 } ``` ### 二、数据结构中的段 1. **线段树(Segment Tree)** 用于高效解决区间查询问题(如区间和/最大值)的二叉树结构: - 每个节点代表一个区间(段) - 支持$O(\log n)$复杂度的区间查询和更新 *示例:* 查询数组区间$[l, r]$的元素和 ```python class SegmentTree: def __init__(self, arr): self.n = len(arr) self.size = 4 * self.n self.tree = [0] * self.size self._build(arr, 0, 0, self.n-1) def _build(self, arr, idx, l, r): if l == r: self.tree[idx] = arr[l] else: mid = (l + r) // 2 self._build(arr, 2*idx+1, l, mid) self._build(arr, 2*idx+2, mid+1, r) self.tree[idx] = self.tree[2*idx+1] + self.tree[2*idx+2] ``` 2. **内存池(Memory Pools)** 将内存预分为固定大小的段(slabs),提升分配效率: - 避免频繁调用`malloc` - 减少内存碎片(如Linux SLAB分配器) ### 三、其他应用场景 1. **网络传输** TCP协议将数据分割成段(segments)传输 2. **文件系统** 日志结构文件系统(如LFS)将写入操作组织成段 3. **GPU编程** 显存分段管理纹理/缓冲区(如OpenGL的VBO) ### 关键特性对比 | 段类型 | 主要用途 | 管理方式 | |--------------|-------------------------|---------------| | 内存分段 | 进程内存隔离 | 硬件MMU | | 线段树 | 区间查询优化 | 树结构维护 | | 内存池分段 | 高效内存分配 | 预分配块链表 | | 网络分段 | 可靠数据传输 | TCP协议栈 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值