2017 南宁网络赛 Overlapping Rectangles (离散化+扫描线/线段树)

题目:https://nanti.jisuanke.com/t/17313

题意:

确定矩形面积。

#include<bits/stdc++.h>
using namespace std;

double x[2002],y[2002];//最多100个矩形,所以最多只有200条横线或纵线
double a[1002][4];//矩形实际坐标
bool cover[2002][2002];
const double EPS = 1e-7;

int cmp(const void * b,const  void * a){//b>a 返回1
    if(fabs(*(double* )b-*(double *)a)<EPS)return 0;
    else if(*(double* )b-*(double *)a>0)return 1;
    else return -1;
}

int main(){
    int n,i,k,j,h1,h2,v1,v2;
    while(scanf("%d",&n) != EOF){
        if(n==0) {
            printf("*\n");
            break;
        }
        for(i=0,k=0;i<n;i++,k++){
            scanf("%lf%lf%lf%lf",&a[i][0],&a[i][1],&a[i][2],&a[i][3]);
            x[k]=a[i][0],y[k]=a[i][1],x[++k]=a[i][2],y[k]=a[i][3];
        }
        qsort(x,2*n,sizeof(x[0]),cmp);
        qsort(y,2*n,sizeof(y[0]),cmp);//将横线,竖线排好序
        memset(cover,0,sizeof(cover));//初始时无覆盖区
        //对每个矩形,进行一次横纵线的扫描,覆盖范围
        //扫描线条数作为下标,离散化
        for(i=0;i<n;i++){
            k=0;
            while(fabs(x[k]-a[i][0])>EPS)k++;h1=k;
            k=0;
            while(fabs(y[k]-a[i][1])>EPS)k++;v1=k;
            k=0;
            while(fabs(x[k]-a[i][2])>EPS)k++;h2=k;
            k=0;
            while(fabs(y[k]-a[i][3])>EPS)k++;v2=k;
            //标记该矩形覆盖的区域
            for(j=h1;j<h2;j++)      //不考虑最右
                for(k=v1;k<v2;k++)  //不考虑最下
                    cover[j][k]=true;
        }
        double sum=0;
        //这时再用扫描线真实的位置计算面积,由矩形左下角的点(判断是否覆盖)及四条扫描线确定。
        for(i=0;i<2*n-1;i++)
            for(j=0;j<2*n-1;j++)
                sum+=(cover[i][j]*(x[i+1]-x[i])*(y[j+1]-y[j]));
        printf("%d\n", (int)round(sum));
    }
}

接下来用线段树做。

用扫描线位置(下标)做权值建线段树。(无需lazy标记)

(加第一条线段时更改的是第一到第二条扫描线的位置,但最后算的是底边为1到3长度的面积)


#include<bits/stdc++.h>
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define ll long long int
using namespace std;

const int maxn = 2000 + 5;
int  col[maxn << 2], n, res;
double sum[maxn << 2],X[maxn << 2];  //沿X轴从左往右扫
struct seg{
    double l,r,h;
    int f;  //下边为1,上边为-1,扫描到上边时减去这个区间
    seg() {}
    seg(double l,double r,double h,int f):l(l),r(r),h(h),f(f) {}
    bool operator < (const seg & object) const {
        return h < object.h;
    }
} S[maxn];

void pushup(int rt,int l,int r){
    if(col[rt]) sum[rt]=X[r+1]-X[l]; //r+1是右端点那条
    else{
        if(l==r) sum[rt]=0;
        else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
}

void update(int L,int R,int c,int rt,int l,int r){
    if(l>=L&&r<=R){
        col[rt]+=c;
        pushup(rt,l,r);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) update(L,R,c,lson);
    if(R>mid) update(L,R,c,rson);
    pushup(rt,l,r);
}

int find(double x){
    int l=-1,r=res-1;
    while(r>=l){
        int mid=(l+r)>>1;
        if(X[mid]>=x) r=mid-1;
        else l=mid+1;
    }
    return r+1;
}
int main(){
    while(scanf("%d",&n) != EOF){
        if(n==0) {
            printf("*\n");
            break;
        }
        int cnt=0;
        for(int i=0;i<n;i++){
            double a,b,c,d;
            cin>>a>>b>>c>>d;
            S[cnt]=seg(a,c,b,1), X[cnt++]=a;
            S[cnt]=seg(a,c,d,-1),X[cnt++]=c;
        }
        sort(X,X+cnt);
        sort(S,S+cnt);
        res=unique(X,X+cnt)-X;  //扫描线去重

        memset(sum,0,sizeof(sum));
        memset(col,0,sizeof(col));
        double ans=0;
        for(int i=0;i<cnt-1;i++){
            int l=find(S[i].l);  //找下标,放入线段树,相当于离散化
            int r=find(S[i].r)-1;  //找右端点左边那条,这里不会有2个以上重叠的部分
            update(l,r,S[i].f,1,0,res-1);
            ans+=sum[1]*(S[i+1].h-S[i].h);
        }
        printf("%d\n", (int)round(ans)); //四舍五入
    }
}

<think>嗯,用户现在想知道之前提到的关于dtb/设备树的修改内容。之前我给出的回答里详细描述了在SPI NAND Flash上划分包含rootfs分区的步骤,其中设备树配置是关键的第一步。用户可能是在实际应用中遇到了问题,需要回顾设备树的修改部分,或者想要更详细地了解每个步骤的具体配置。 首先,我需要确认用户的需求。他们可能正在尝试在自己的项目中实现类似的分区,但可能对设备树的修改不太熟悉,或者遇到了配置上的问题。用户提到的“上记全部关于dtb/设备树的修改”指的是之前回答中有关设备树的部分,特别是设备树源文件(dts)中的配置。 接下来,我需要回顾之前的回答,提取所有涉及设备树修改的部分。之前的回答中,Step 1是设备树分区配置,给出了一个分区的示例,包括各个分区的起始地址、大小和标签。此外,Step 4中的两种方案(传统块设备和UBI卷方式)也涉及到了设备树的修改,比如为UBI卷添加分区配置。 用户可能需要更详细的解释,每个分区的含义,地址和大小的计算方式,以及兼容性设置等。他们可能想知道为什么选择特定的起始地址和大小,如何确保不与其他分区重叠,或者如何适配自己的硬件。此外,可能还需要了解设备树中各个参数的作用,例如`compatible`、`#address-cells`、`#size-cells`等。 另外,用户可能对设备树如何与内核配置和驱动交互感兴趣。例如,设备树中的分区信息如何被内核识别,如何确保驱动正确读取这些分区,以及如何处理NAND Flash的特殊需求,如ECC配置和坏块管理。 可能的疑问点包括:如何确定分区的起始地址和大小?如果Flash的总容量不同,应该如何调整?如何处理多个分区之间的间隙?为什么推荐使用UBI卷方式?设备树中的`reg`属性是如何计算的?这些问题都需要在回答中详细说明,以帮助用户更好地理解和应用。 我还需要检查之前的设备树示例是否有潜在的错误或遗漏,例如分区的地址是否连续,大小是否正确,是否有保留空间等。例如,示例中的rootfs分区从0x800000开始,大小为0x7800000,换算成十进制是120MB,而用户数据分区从0x8000000开始,可能需要确认总容量是否足够,是否有地址溢出。 此外,用户可能在应用示例代码时遇到了编译或运行时的问题,需要了解如何调试设备树配置,例如通过检查生成的dtb文件,或者使用工具如fdtdump来验证分区信息是否正确。 总结来说,用户需要的是关于设备树修改的详细解释,包括各个参数的意义、配置的注意事项,以及如何验证配置的正确性。需要确保回答清晰、结构合理,涵盖所有相关的设备树修改点,并解释其背后的原理,以帮助用户正确应用在自己的项目中。</think>以下是关于设备树(DTB)修改的完整说明,主要包含分区定义、UBI配置和NAND特性设置三个核心部分: --- ### **一、基础分区定义** ```dts &nand_flash { partitions { compatible = "fixed-partitions"; // 固定分区模式 #address-cells = <1>; // 地址用单cell表示 #size-cells = <1>; // 大小用单cell表示 /* 必须保留的头部空间 */ partition@0 { label = "spl"; // 二级引导程序 reg = <0x0 0x200000>; // 起始地址0x0,大小2MB }; partition@200000 { label = "uboot-env"; // U-Boot环境变量区 reg = <0x200000 0x100000>; // 起始地址2MB,大小1MB }; partition@300000 { label = "kernel"; // 内核镜像区 reg = <0x300000 0x500000>; // 起始地址3MB,大小5MB }; }; }; ``` --- ### **二、RootFS分区配置** #### **方案A:传统块设备模式** ```dts partition@800000 { label = "rootfs"; reg = <0x800000 0x7800000>; // 起始地址8MB,大小120MB read-only; // 只读属性 }; ``` #### **方案B:UBI高级模式(推荐)** ```dts partition@800000 { label = "ubi"; // 必须命名为ubi reg = <0x800000 0x7800000>; // UBI卷容器 }; ``` --- ### **三、UBI相关配置增强** ```dts / { chosen { /* 内核启动参数注入 */ bootargs = "root=ubi0:rootfs rootfstype=ubifs ubi.mtd=ubi"; }; }; /* NAND控制器补充配置 */ &nand_controller { #address-cells = <1>; #size-cells = <0>; ecc-engine = <&ecc>; // 指定ECC引擎 }; ``` --- ### **四、关键参数解析** | 参数 | 值 | 作用说明 | |----------------------|---------------|--------------------------------------------------------------------------| | `compatible` | fixed-partitions | 声明固定分区模式 | | `#address-cells` | 1 | 地址用32位整数表示 | | `#size-cells` | 1 | 大小用32位整数表示 | | `reg` | <起始 大小> | 必须用十六进制表示,例如`<0x800000 0x7800000>`表示起始8MB,大小120MB | | `read-only` | - | 防止意外写入的关键分区 | --- ### **五、地址计算规则** ```text 总容量 = 0x8000000 (128MB) + 0x8000000 (128MB) = 256MB 各分区地址范围: - spl: 0x000000 - 0x1FFFFF (2MB) - uboot-env: 0x200000 - 0x2FFFFF (1MB) - kernel: 0x300000 - 0x7FFFFF (5MB) - ubi: 0x800000 - 0x7FFFFFF (120MB) - userdata: 0x8000000 - 0xFFFFFFFF (128MB) ``` --- ### **六、验证方法** 1. **编译检查**: ```bash fdtdump dtb_file | grep -A 15 nand_flash ``` 2. **运行时验证**: ```bash # 查看内核解析的分区 cat /proc/mtd # 输出示例: mtd3: 07800000 00020000 "ubi" ``` 3. **UBI状态确认**: ```bash ubinfo -a # 预期显示: Volume ID: 0 (on ubi0) Type: dynamic Name: rootfs ``` --- ### **七、常见问题处理** #### **问题1:地址重叠** ```text 错误现象:内核启动时提示"overlapping partitions" 解决方案:使用十六进制计算器重新核对reg参数,确保: 前一个分区的起始地址 + 大小 ≤ 下一个分区的起始地址 ``` #### **问题2:UBI无法附加** ```dts // 增加UBI保留块配置 partition@800000 { label = "ubi"; reg = <0x800000 0x7800000>; compatible = "linux,ubi"; // 显式声明UBI兼容性 }; ``` --- 通过上述配置,可实现: 1. 精确控制NAND物理布局 2. 硬件ECC与坏块管理联动 3. UBI卷的动态可扩展性 4. 内核启动参数的自动注入 最终可通过设备树反编译验证: ```bash dtc -I dtb -O dts -o recon.dts system.dtb grep -n "nand_flash" recon.dts ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值