【ACM-ICPC 2018 徐州赛区网络预赛 G. Trace】 离散化+权值线段树

题目链接
https://nanti.jisuanke.com/t/31459
题意
题 意 就 是 按 顺 序 给 出 一 些 左 下 角 在 原 点 的 与 坐 标 轴 平 行 的 矩 形 , 题意就是按顺序给出一些左下角在原点的与坐标轴平行的矩形,
后 来 的 矩 形 会 覆 盖 掉 原 来 矩 形 的 边 , 求 最 后 所 有 能 看 见 的 边 的 总 长 度 。 后来的矩形会覆盖掉原来矩形的边,求最后所有能看见的边的总长度。
*做法
正 向 做 应 该 很 难 想 , 我 们 考 虑 最 后 一 个 添 加 的 矩 形 一 定 是 完 整 的 , 正向做应该很难想,我们考虑最后一个添加的矩形一定是完整的,
而 对 于 之 后 的 矩 形 我 们 只 要 把 两 条 边 分 开 考 虑 , 而对于之后的矩形我们只要把两条边分开考虑,
与 x 轴 平 行 的 边 对 答 案 能 做 的 贡 献 为 x i − 他 所 在 的 y 的 最 大 的 x 与x轴平行的边对答案能做的贡献为xi-他所在的y的最大的x xxiyx
与 y 轴 平 行 的 边 对 答 案 能 做 的 贡 献 为 y i − 他 所 在 的 x 的 最 大 的 y 与y轴平行的边对答案能做的贡献为yi-他所在的x的最大的y yyixy
我 们 对 x , y 分 别 离 散 化 建 立 权 值 线 段 树 我们对x,y分别离散化建立权值线段树 x,y线
每 次 先 查 询 每 条 边 所 能 做 的 贡 献 每次先查询每条边所能做的贡献
更 新 0 − x i 之 间 的 y 的 m a x , 更 新 0 − y i 之 间 的 x 的 m a x 更新0-xi之间的y的max,更新0-yi之间的x的max 0xiymax,0yixmax
单 点 查 询 区 间 更 新 , 用 L a z y 就 可 以 做 到 O ( n l o g n ) 单点查询区间更新,用Lazy就可以做到O(nlogn) LazyO(nlogn)
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
const int maxn = 1e5+10;
int x[maxn],y[maxn];
int Hash_x[maxn],Hash_y[maxn];
int getid(int a[],int n,int x)
{
    return lower_bound(a+1,a+1+n,x)-a;
}
struct T
{
    int l,r,mid,val;
    int add;
}tree_x[maxn<<2],tree_y[maxn<<2];
void push_up(T tree[],int rt)
{
    tree[rt].val=max(tree[rt<<1].val,tree[rt<<1|1].val);
}
void push_down(T tree[],int rt)
{
    if(tree[rt].add)
    {
        tree[rt<<1].add=max(tree[rt<<1].add,tree[rt].add);
        tree[rt<<1].val=max(tree[rt<<1].val,tree[rt].add);
        tree[rt<<1|1].add=max(tree[rt<<1|1].add,tree[rt].add);
        tree[rt<<1|1].val=max(tree[rt<<1|1].val,tree[rt].add);
        tree[rt].add=0;
    }
}

void build(T tree[],int rt,int l,int r)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].add=0;
    if(l==r) return ;
    int mid=tree[rt].mid=l+r>>1;
    build(tree,rt<<1,l,mid);
    build(tree,rt<<1|1,mid+1,r);
    push_up(tree,rt);
}

void update(T tree[],int rt,int l,int r,int val)
{
    if(r<tree[rt].l||l>tree[rt].r)  return ;
    if(l<=tree[rt].l&&tree[rt].r<=r)
    {
        tree[rt].add=max(tree[rt].add,val);
        tree[rt].val=max(tree[rt].val,val);
        return ;
    }
    push_down(tree,rt);
    if(l<=tree[rt].mid) update(tree,rt<<1,l,r,val);
    if(r>tree[rt].mid) update(tree,rt<<1|1,l,r,val);
    push_up(tree,rt);
}

int query(T tree[],int rt,int pos)
{
    if(tree[rt].l==tree[rt].r)  return tree[rt].val;
    push_down(tree,rt);
    long long ans;
    if(pos<=tree[rt].mid) ans=query(tree,rt<<1,pos);
    else ans=query(tree,rt<<1|1,pos);
    push_up(tree,rt);
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
    for(int i=1;i<=n;i++)
    {
        Hash_x[i]=x[i];
        Hash_y[i]=y[i];
    }
    sort(Hash_x+1,Hash_x+1+n);
    sort(Hash_y+1,Hash_y+1+n);
    int d_x=unique(Hash_x+1,Hash_x+1+n)-Hash_x-1;
    int d_y=unique(Hash_y+1,Hash_y+1+n)-Hash_y-1;
    build(tree_x,1,1,d_x);
    build(tree_y,1,1,d_y);
    long long ans=0;
    for(int i=n;i>=1;i--)
    {
        int posx=getid(Hash_x,d_x,x[i]);
        int posy=getid(Hash_y,d_y,y[i]);
        int tmp=query(tree_x,1,posx);
        if(tmp<y[i]) ans+=y[i]-tmp;
        tmp=query(tree_y,1,posy);
        if(tmp<x[i]) ans+=x[i]-tmp;
        update(tree_x,1,1,posx,y[i]);
        update(tree_y,1,1,posy,x[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值