[模板] 三维偏序 - 树套树,线段树

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

const int N = 2e+7 + 5;

struct Pt {
    int a, b, c;
    int id;
    bool operator<(const Pt &x) const { return a < x.a; }
} p[N];

map<int, int> ma, mb, mc;
int aa[N], ab[N], ac[N];
int ida, idb, idc;
int n;
int ans[N];

namespace segc {
int val[N], ch[N][2], root[N], ind;
void pushup(int p) { val[p] = val[ch[p][0]] + val[ch[p][1]]; }
void modify(int p, int l, int r, int pos) {
    if (l == r) {
        val[p]++;
    } else {
        if (pos <= (l + r) / 2) {
            if (!ch[p][0])
                ch[p][0] = ++ind;
            modify(ch[p][0], l, (l + r) / 2, pos);
        } else {
            if (!ch[p][1])
                ch[p][1] = ++ind;
            modify(ch[p][1], (l + r) / 2 + 1, r, pos);
        }
        pushup(p);
    }
}
void modify(int ver, int pos) {
    if (!root[ver])
        root[ver] = ++ind;
    modify(root[ver], 1, n, pos);
}
int query(int p, int l, int r, int ql, int qr) {
    if (l > qr || r < ql || p == 0)
        return 0;
    if (l >= ql && r <= qr)
        return val[p];
    return query(ch[p][0], l, (l + r) / 2, ql, qr) + query(ch[p][1], (l + r) / 2 + 1, r, ql, qr);
}
int query(int ver, int ql, int qr) { return query(root[ver], 1, n, ql, qr); }
}  // namespace segc

namespace segb {
void modify(int p, int l, int r, int pos, int posi) {
    segc::modify(p, posi);
    if (l != r) {
        if (pos <= (l + r) / 2)
            segb::modify(p * 2, l, (l + r) / 2, pos, posi);
        else
            segb::modify(p * 2 + 1, (l + r) / 2 + 1, r, pos, posi);
    }
}
void modify(int pos, int posi) { modify(1, 1, n, pos, posi); }
int query(int p, int l, int r, int ql, int qr, int iql, int iqr) {
    if (l > qr || r < ql)
        return 0;
    if (l >= ql && r <= qr)
        return segc::query(p, iql, iqr);
    return query(p * 2, l, (l + r) / 2, ql, qr, iql, iqr) +
           query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, iql, iqr);
}
int query(int ql, int qr, int iql, int iqr) { return query(1, 1, n, ql, qr, iql, iqr); }
}  // namespace segb

int k;

signed main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d%d", &p[i].a, &p[i].b, &p[i].c);
        ma[p[i].a]++;
        mb[p[i].b]++;
        mc[p[i].c]++;
        p[i].id = i;
    }
    for (map<int, int>::iterator it = ma.begin(); it != ma.end(); it++)
        it->second = ++ida, aa[ida] = it->first;
    for (map<int, int>::iterator it = mb.begin(); it != mb.end(); it++)
        it->second = ++idb, ab[idb] = it->first;
    for (map<int, int>::iterator it = mc.begin(); it != mc.end(); it++)
        it->second = ++idc, ac[idc] = it->first;
    for (int i = 1; i <= n; i++) {
        p[i].a = ma[p[i].a];
        p[i].b = mb[p[i].b];
        p[i].c = mc[p[i].c];
    }

    sort(p + 1, p + n + 1);
    for (int i = 1; i <= n;) {
        int j;
        for (j = i; j <= n; j++)
            if (p[i].a != p[j].a)
                break;
        --j;
        for (int k = i; k <= j; k++) segb::modify(p[k].b, p[k].c);
        for (int k = i; k <= j; k++) {
            ans[segb::query(1, p[k].b, 1, p[k].c)]++;
        }
        i = j + 1;
    }
    for (int i = 1; i <= n; i++) printf("%d\n", ans[i]);
}

原文地址:https://www.cnblogs.com/mollnn/p/11785214.html

时间: 2024-08-03 04:36:04

[模板] 三维偏序 - 树套树,线段树的相关文章

BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

题目大意:有一些位置,这些位置上可以放若干个数字.现在有两种操作. 1.在区间l到r上添加一个数字x 2.求出l到r上的第k大的数字是什么 思路:这种题一看就是树套树,关键是怎么套,怎么写.(话说我也不会来着..)最容易想到的方法就是区间线段树套一个权值线段树,但是区间线段树上的标记就会变得异常复杂.所以我们就反过来套,用权值线段树套区间线段树.这样修改操作在外线段树上就变成了单点修改,外线段树就不用维护标记了.在里面的区间线段树上维护标记就容易多了.具体实现见代码. CODE: #includ

【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43020009"); } 题解: 外层权值线段树,内层区间线段树可解. 权值都是1~n,就不用离散化了. 我写了标记永久化. 其它心得神马的: 天生对树形数据结构无爱. 第一次写树套树,终于知道是怎么回事了. (只针对本题) 就是外层每个点都表示了一段

Codeforces 780G Andryusha and Nervous Barriers 线段树套set || 线段树套单调栈

Andryusha and Nervous Barriers 问题本质我们只需要找出每个线段两端下面第一个碰到的是哪个线段就好啦. 按照 h 排序我们就能用线段树套set 不管维护什么都能维护出这个东西,但是 如果set里维护 u + s的话,就能优化成单调栈, 好优秀啊. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi f

【BZOJ3110】【codevs1616】K大数查询,权值线段树套普通线段树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门1 传送门2 思路: 之前没怎么接触过权值线段树(非主席树),这次就当学习了一下吧.一开始还把题意理解错了,我的天啊-- 起初思考了好久,发现不知道怎么处理负数的情况,不过数据里并没有负数? 权值线段树的每个节点表示一个区间[L,R],存储原序列中权值为[L,R]的元素的信息,所以这里的权值线段树每个节点上都是一棵普通线段树,就是负责统计原序列中权值为[L,R]的元素的个数. 每次插入一个相同的值x时就相当于

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #inc

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

HDU4897 (树链剖分+线段树)

Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作2:将所有 有且仅有一个点在a->b的路径中 的边的颜色翻转. 操作3:询问a->b的路径中的黑色边数量. 解题分析 考虑操作1,只需正常的树链剖分+线段树维护即可.用线段树维护每条边,tag_1[i]表示该区间中的黑色边数量. 考虑操作2,一个节点相邻的边只可能为重链和轻链,且重链的数目小于等于

【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1". 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n