HDU 1828 Picture

重叠矩形周长计算
本文介绍了一种使用扫描线算法解决二维平面上多个矩形重叠问题的方法,通过构建线段树来高效地计算所有重叠矩形的边界长度。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828


题意:求重叠矩形的周长


思路:也是运用了扫描线,每一次更新后的tsum减去之前的tsum就是这次周长增长(上边处理理解有些不同,画了张图理解),由于周长要计算所有的边要到cnt(面积只要到cnt-1


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 20030
using namespace std;

struct Tree
{
    int l,r;
    int tsum,snum;
}tree[maxn*3];

int lazy[maxn*3],lseg[maxn*3],rseg[maxn*3],cnt,pos[maxn];

struct Node
{
    int l,r,h,date;
}s[maxn];

bool cmp(Node p,Node q)
{
    return p.h<q.h;
}

void getlen(int root)
{
    if(lazy[root])
    {
        tree[root].tsum=pos[tree[root].r+1]-pos[tree[root].l];
        lseg[root]=1;
        rseg[root]=1;
        tree[root].snum=2;
    }
    else if (tree[root].l==tree[root].r)
    {
        tree[root].tsum=0;
        lseg[root]=0;
        rseg[root]=0;
        tree[root].snum=0;
    }
    else
    {
        tree[root].tsum=tree[root<<1].tsum+tree[root<<1|1].tsum;
        tree[root].snum=tree[root<<1].snum+tree[root<<1|1].snum;
        lseg[root]=lseg[root<<1];
        rseg[root]=rseg[root<<1|1];
        if (rseg[root<<1] && lseg[root<<1|1]) tree[root].snum-=2;
    }
}

void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].tsum=tree[root].snum=0;
    if (l==r) return;
    int mid=(tree[root].l+tree[root].r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}

void update(int root,int l,int r,int val)
{
    if (tree[root].l>=l && tree[root].r<=r)
    {
        lazy[root]+=val;
        getlen(root);
        return;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if (l<=mid) update(root<<1,l,r,val);
    if (r>mid) update(root<<1|1,l,r,val);
    getlen(root);
}

void getline(int l,int r,int h,int val)
{
    s[cnt].l=l;
    s[cnt].r=r;
    s[cnt].h=h;
    s[cnt].date=val;
    cnt++;
}


int main()
{
    int n,num;
    while (scanf("%d",&n)!=EOF)
    {
        cnt=0;
        num=0;
        memset(lazy,0,sizeof(lazy));
        memset(lseg,0,sizeof(lseg));
        memset(rseg,0,sizeof(rseg));
        for (int i=0;i<n;i++)
        {
            int x1,x2,y1,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            getline(x1,x2,y1,1);
            getline(x1,x2,y2,-1);
            pos[num++]=x1;
            pos[num++]=x2;
        }
        sort(s,s+cnt,cmp);
        sort(pos,pos+num);

        int tem=1,last=0,res=0;
        for (int i=1;i<num;i++)
        {
            if (pos[i]!=pos[i-1])
             pos[tem++]=pos[i];
        }
        build(1,0,tem);
        s[cnt].h=s[cnt-1].h;
        for (int i=0;i<cnt;i++)
        {
            int l=lower_bound(pos,pos+tem,s[i].l)-pos;
            int r=lower_bound(pos,pos+tem,s[i].r)-pos-1;
            update(1,l,r,s[i].date);
            res+=abs(last-tree[1].tsum);
            res+=tree[1].snum*(s[i+1].h-s[i].h);
            last=tree[1].tsum;
        }
        printf("%d\n",res);
    }
}


),snum是来保存没有被覆盖的竖边,lseg和rseg是标记该区间是否被覆盖,如果左子树的rseg和右子树的lseg被覆盖就代表有2个矩形是重叠的因此snum数目需要-2



扫描线走到A的时候,将边1的区间标记,tsum加上边1的长度(初始为0),减去last的长度(初始为0)

扫描线走到B的时候,将边2的区间标记,tsum加上边2没有和边1重合的长度,减去last长度(上一步的tsum)

扫描线走到C的时候,和上2步类似

扫描线走到D的时候,由于边4是上边,边4的区间标记-1,但是由于其他边已经覆盖该区间,tsum没有影响

扫描线走到E的时候,边5的区间-1,tsum减去标记为0的区间,在和last的差值就是该位置增加的区间



第五届广西省大学生程序设计竞赛K Kirby's challenge(AC代码) 分数 300 作者 Colin 单位 杭州电子科技大学 Description Recently, Colin bought a Switch for Eva. And they are playing "Kirby and the Forgotten Land". In a challenge mission, Kirby is in a 4×n grid. The row of it is numbered from 1 to 4, and the column of it is numbered from 1 to n. There are many keys in this grid. Let a x,y ​ represent the status of cell (x,y). If a x,y ​ =1, there is a key in (x,y). If a x,y ​ =0, there is no key in (x,y). Kirby starts at (1,1), and should reach (4,n). Moreover, Kirby must collect all the keys in the grid to open the door in (4,n). Kirby will collect the key at (x,y) when Kirby reach (x,y). Of course, Kirby will collect the key at (1,1) at the beginning. In a second, Kirby can move from (x,y) to (x+1,y),(x,y+1),(x−1,y). Or Kirby can stay at (x,y) and throw a returnable flying weapon(boomerang) to collect keys in the flying path. Kirby has two ways to throw the weapon. As the picture shows: image-20220604213457062.png The flying path is represented as the grey cells, so keys in the grey cells can be collected by the weapon. In a second, Kirby can only choose one way to throw the weapon, but Kirby can throw the weapon multiple times at (x,y) if necessary. Notice: Kirby can't get off the grid, but the weapon can fly outside the grid and keep the flying path. Please write a program to help Colin and Eva find the shortest time to complete the challenge mission, so that they can get more rewards. Input The first line contains one integer n (1≤n≤100). In the next 4 lines, the x-th line contains n integers a x,1 ​ ,a x,2 ​ ,⋯,a x,n ​ (0≤a x,y ​ ≤1). Output Print one integer representing the minimum number of seconds required to complete the challenge mission. Sample input 1 5 1 1 1 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 1 output 1 8 The best solution is: Spend 1 second to throw the weapon in the second way at (1,1), and spend 7 seconds to reach (4,5). 代码长度限制 16 KB 时间限制 1000 ms 内存限制 512 MB 栈限制 131072 KB
最新发布
08-09
在程序设计竞赛中,寻找特定题目的解题思路及 AC(Accepted)代码通常可以从比赛的官方题解、参赛选手的博客、GitHub 仓库以及在线评测系统的讨论区中获取。对于第五届广西省大学生程序设计竞赛 K 题 *Kirby's challenge*,可以通过以下方式尝试获取相关信息: ### 题目理解与解题思路 *Kirby's challenge* 的核心问题通常涉及算法设计与数据结构的应用,例如动态规划、图论、字符串处理或数学建模等。由于该题目的具体描述未公开,以下是一般性建议用于分析类似题目的方法: 1. **阅读题目要求**:明确输入输出格式、约束条件以及目标函数。 2. **分析问题模型**:将题目抽象为图、数组、字符串等结构,并选择合适的算法进行建模。 3. **时间与空间复杂度分析**:确保算法在给定数据范围下可以高效运行。 4. **编写代码并测试**:实现算法后,在本地进行多组测试以验证逻辑正确性。 ### 获取 AC 代码的途径 1. **比赛题解文档**:通常比赛结束后,主办方会在其官方网站或相关平台上发布题解文档,其中包含各题的解法与参考代码。 2. **GitHub 仓库**:许多参赛者会将比赛 AC 代码上传至 GitHub。可以尝试搜索关键词如“第五届广西省大学生程序设计竞赛 K题”或“Kirby's challenge AC code”。 3. **OJ 平台提交记录**:如果该题目曾在在线评测系统(如 HDU、ZOJ、Codeforces Gym)中开放练习,可以通过查看该题的提交记录找到 AC 提交的代码。 4. **社区与博客平台**:优快云、知乎、洛谷、牛客网等平台常有参赛者撰写比赛题解,搜索相关关键词可能会找到详细解析和代码实现。 ### 示例代码结构(假设为动态规划问题) 以下是一个伪代码示例,展示如何组织类似题目的代码结构: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; int dp[MAXN]; int a[MAXN]; int main() { int n; cin >> n; for (int i = 0; i < n; ++i) { cin >> a[i]; } // 初始化 dp 数组 dp[0] = a[0]; for (int i = 1; i < n; ++i) { dp[i] = max(dp[i-1] + a[i], a[i]); } // 输出结果 cout << *max_element(dp, dp + n) << endl; return 0; } ``` ### 注意事项 - **代码风格**:保持良好的命名习惯与注释风格,有助于他人理解与复用。 - **算法优化**:在比赛中,注意常数优化与数据结构的选择,以通过时间限制。 - **测试用例**:在提交前应准备边界测试用例,确保程序鲁棒性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值