poj 1436 Horizontally Visible Segments(线段树基础,区间染色,拆点)

本文介绍了一种解决区间覆盖及可见性问题的方法,通过排序和分段树更新策略实现。重点讨论了如何处理整数间视线遮挡的情况,并通过拆点等技巧优化算法效率。

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

题意:
。。。
思路:
首先按x排序,,
然后一条一条覆盖上去,当前为i,如果可以同时看到x和y,且x和y互相能看到,答案加1。。
统计的部分暴力就能ac。。
关键点:相邻整数之间的部分被当作看不见了。。不如x相同的两条
(1, 2) (3, 3)…(2, 3)之间其实是可以看过去的,所以要拆点。

int xi[Maxn], y1i[Maxn], y2i[Maxn], rk[Maxn];
bool ma[Maxn][Maxn];

#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
struct node {
    int cover;
};
node a[Maxn*8+5];

void push_down(int o) {
    if (a[o].cover != -1) {
        a[lson(o)].cover = a[rson(o)].cover = a[o].cover;
        a[o].cover = -1;
    }
}

set<int> s;

void seg_update(int L, int R, int o, int qL, int qR, int v) {
    int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
    if (qL <= L && R <= qR) {
        if (a[o].cover != -1) {
            if (xi[a[o].cover] != xi[v]) s.insert(a[o].cover);
        } else {
            if (L < R) {
                seg_update(L, mid, lc, qL, qR, v);
                seg_update(mid+1, R, rc, qL, qR, v);
            }
        }
        a[o].cover = v;
        return;
    }

    push_down(o);
    if (qL <= mid) seg_update(L, mid, lc, qL, qR, v);
    if (qR > mid) seg_update(mid+1, R, rc, qL, qR, v);
}

void seg_build(int L, int R, int o) {
    a[o] = (node) {-1};
    if (L == R) {
        int kk = 0;
        ++kk;
    }
    if (L < R) {
        int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
        seg_build(L, mid, lc);seg_build(mid+1, R, rc);
    }
}

int calc(int x) {
    if (s.empty()) return 0;
    vector<int> v;
    set<int>::iterator it = s.begin();
    for (;it != s.end();++it) {
        v.push_back(*it);
        ma[x][*it] = ma[*it][x] = 1;
    }
    //printf("%d can see: ", x);for (int i=0;i<v.size();++i) printf("%d ", v[i]);printf("\n");
    int sz = v.size(), ret = 0;
    rep(i, 0, sz-1) rep(j, i+1, sz-1) if (ma[v[i]][v[j]]) ++ret;
    return ret;
}

bool cmp(int lhs, int rhs) {
    return xi[lhs] < xi[rhs];
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif // ONLINE_JUDGE
    int t, n, N = 2*Maxn;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        seg_build(1, N, 1);
        memset(ma, 0, sizeof(ma));

        rep(i, 1, n) {
            scanf("%d%d%d", &y1i[i], &y2i[i], &xi[i]);
            y1i[i] *= 2;y2i[i] *= 2;
            ++y1i[i];++y2i[i];
            rk[i] = i;
        }

        sort(rk+1, rk+1+n, cmp);

        int ans = 0;
        rep(i, 1, n) {
            int x = rk[i];
            //printf("dye%d: (%d %d) %d:\n", x, y1i[x], y2i[x], xi[x]);
            s.clear();
            seg_update(1, N, 1, y1i[x], y2i[x], x);
            ans += calc(x);
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值