bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】
模板题,折腾了许久。
cqd分治整体二分,感觉像是把询问分到答案上。
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drep(i, a, b) for (int i = a; i >= b; i--)
#define REP(i, a, b) for (int i = a; i < b; i++)
#define pb push_back
#define mp make_pair
#define clr(x) memset(x, 0, sizeof(x))
#define xx first
#define yy second
using namespace std;
typedef long long i64;
typedef pair<int, int> pii;
const int inf = ~0U >> ;
const i64 INF = ~0ULL >> ;
template <typename T> void Max(T &a, T &b) { if (a < b) a = b; }
template <typename T> void Min(T &a, T &b) { if (a > b) a = b; }
//****************************************** const int maxn = ; struct Seg_Tree {
int sum[maxn << ], lazy[maxn << ];
void Push_down(int o, int m) {
if (!lazy[o]) return;
lazy[o << ] += lazy[o], lazy[o << | ] += lazy[o];
sum[o << ] += lazy[o] * (m - (m >> )), sum[o << | ] += lazy[o] * (m >> );
lazy[o] = ;
}
void Push_up(int o) { sum[o] = sum[o << ] + sum[o << | ]; }
void update(int o, int l, int r, int ql, int qr, int v) {
if (ql <= l && r <= qr) {
lazy[o] += v;
sum[o] += v * (r - l + );
return;
}
Push_down(o, r - l + );
int mid = l + r >> ;
if (ql <= mid) update(o << , l, mid, ql, qr, v);
if (qr > mid) update(o << | , mid + , r, ql, qr, v);
Push_up(o);
}
int query(int o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return sum[o];
Push_down(o, r - l + );
int mid = l + r >> ;
int ret();
if (ql <= mid) ret += query(o << , l, mid, ql, qr);
if (qr > mid) ret += query(o << | , mid + , r, ql, qr);
return ret;
}
void CLR() { clr(sum), clr(lazy); }
} T; struct Complex {
int flag, x, y, c, id;
inline bool operator < (const Complex &A) const {
return id < A.id;
}
} src[maxn]; int N, ans[maxn], v[maxn];
void cdq(int ansl, int ansr, int l, int r) {
if (ansl == ansr) {
rep(i, l, r) if (src[i].flag == ) ans[src[i].id] = ansl;
return;
}
if (l > r) return;
sort(src + l, src + r + );
int m = ansl + ansr + >> ;
int j = l;
rep(i, l, r) {
if (src[i].flag == ) {
if (src[i].c >= m) T.update(, , N, src[i].x, src[i].y, ), v[i] = ;
else v[i] = ;
}
else {
int t = T.query(, , N, src[i].x, src[i].y);
if (t >= src[i].c) v[i] = ;
else src[i].c -= t, v[i] = ;
}
j += !v[i];
}
rep(i, l, r)
if (src[i].flag == )
if (src[i].c >= m) T.update(, , N, src[i].x, src[i].y, -);
int t = j - ;
if (j != l)
rep(i, l, t) {
while (j < r && v[j]) ++j;
if (v[i]) swap(src[i], src[j]), swap(v[i], v[j]), ++j;
}
cdq(ansl, m - , l, t);
cdq(m, ansr, t + , r);
} int read() {
int l = , s = ; char ch = getchar();
while (ch < '' || ch > '') { if (ch == '-') l = -; ch = getchar(); }
while (ch >= '' && ch <= '') { s = (s << ) + (s << ) + ch - ''; ch = getchar(); }
return s * l;
}
int main() {
int n, m; scanf("%d%d", &n, &m);
rep(i, , m) scanf("%d%d%d%d", &src[i].flag, &src[i].x, &src[i].y, &src[i].c), src[i].id = i;
N = n;
cdq(-n, n, , m);
sort(src + , src + + m);
rep(i, , m) if (src[i].flag == ) printf("%d\n", ans[i]);
return ;
}
树套树本来想把代表区间的那个线段树开在外面,不是不可以,但是lazy标记可能要一个vector才能存,因为我要存多个种类。
然后就只能把代表数字那一维开在外面,代表这一段数字在1-n这个区间的分布情况,这样就可以在第二层线段树上打lazy标记。
#include <bits/stdc++.h>
#define rep(i, a, b) for (register int i = a; i <= b; i++)
#define drep(i, a, b) for (register int i = a; i >= b; i--)
#define REP(i, a, b) for (register int i = a; i < b; i++)
#define pb push_back
#define mp make_pair
#define clr(x) memset(x, 0, sizeof(x))
#define xx first
#define yy second
using namespace std;
typedef long long i64;
typedef pair<int, int> pii;
const int inf = ~0U >> ;
const i64 INF = ~0ULL >> ;
//******************************* const int maxn = , maxnn = ; int root[maxn << ];
int ls[maxnn], rs[maxnn], sum[maxnn], lazy[maxnn]; int ndtot, n, N;
inline void Push_up(int o) { sum[o] = sum[ls[o]] + sum[rs[o]]; }
inline void Push_down(int o, int m) {
if (!lazy[o]) return;
if (!ls[o]) ls[o] = ++ndtot;
if (!rs[o]) rs[o] = ++ndtot;
lazy[ls[o]] += lazy[o], lazy[rs[o]] += lazy[o];
sum[ls[o]] += lazy[o] * (m - (m >> )), sum[rs[o]] += lazy[o] * (m >> );
lazy[o] = ;
}
void update(int &k, int l, int r, int ql, int qr, int v) {
if (!k) k = ++ndtot;
if (ql <= l && r <= qr) {
sum[k] += v * (r - l + );
lazy[k] += v;
return;
}
int mid = l + r >> ;
Push_down(k, r - l + );
if (ql <= mid) update(ls[k], l, mid, ql, qr, v);
if (qr > mid) update(rs[k], mid + , r, ql, qr, v);
Push_up(k);
}
void insrt(int o, int l, int r, int ql, int qr, int c) {
while (l != r) {
int mid = l + r >> ;
update(root[o], , n, ql, qr, );
if (c <= mid) o <<= , r = mid;
else o = o << | , l = mid + ;
}
update(root[o], , n, ql, qr, );
} int query(int o, int l, int r, int ql, int qr) {
if (!o) return ;
if (ql <= l && r <= qr) return sum[o];
Push_down(o, r - l + );
int mid = l + r >> ;
int ret();
if (ql <= mid) ret += query(ls[o], l, mid, ql, qr);
if (qr > mid) ret += query(rs[o], mid + , r, ql, qr);
return ret;
}
int solve(int o, int l, int r, int ql, int qr, int c) {
while (l != r) {
int mid = l + r >> ;
int t = query(root[o << | ], , n, ql, qr);
if (t >= c) l = mid + , o = o << |;
else r = mid, o = o << , c -= t;
}
return l;
} int main() {
int m; scanf("%d%d", &n, &m);
N = * n + ;
while (m--) {
int flag, a, b, c; scanf("%d%d%d%d", &flag, &a, &b, &c);
if (flag == ) {
c += n + ;
insrt(, , N, a, b, c);
}
else printf("%d\n", solve(, , N, a, b, c) - n - );
}
}
bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】的更多相关文章
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...
- BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- [BZOJ3110] [Zjoi2013] K大数查询 (树套树)
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...
- 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- BZOJ3110: [Zjoi2013]K大数查询
喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...
- bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
//========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/ 转载要声明! //=============== ...
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
- 【树套树】bzoj3110 [Zjoi2013]K大数查询
题解很多,实现起来以外地简洁.内层的区间线段树上用了标记永久化. #include<cstdio> using namespace std; #define N 50001 struct ...
随机推荐
- Trie/Xor
题目链接 /*有一个数组a1,a2,a3--an.找到一个连续子段[l,r],使得al ^ al+1 ^--^ ar达到最大. 一般思路:维护前缀异或+暴力: for(int i=1;i<=n; ...
- Webdriver中实现区域截图的方式以及如何截取frame中的图片
import java.awt.Rectangle;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOE ...
- JS-DOM操作应用
父级.appendChild(子节点) 父级.insertBefore(子节点,在谁之前) <title>无标题文档</title> <script> window ...
- ubuntu apache 安装awstats 流量分析工具(命令方式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- 微信小程序页面-页面跳转失败WAService.js:3 navigateTo:fail url not in app.json
微信小程序新建页面的要素一是新建的文件名称和其子文件的名称最好一致,不然容易出问题,在小程序页面跳转中如果出现WAService.js:3 navigateTo:fail url not in app ...
- 使用FusionCharts出柱状图和饼状图
在最近的项目中,需要使用出图,能够查看柱状图,饼状图等效果,刚开始我们用JS写的效果,发现效果不理想,找了一个JS插件发现效果还是不理想,客户也不满意,客户希望要很炫的效果,最后我们使用了Fusion ...
- android脚步---使用framelayout实现霓虹灯效果
轮换帧布局中7个TextView的背景颜色,会出现上面颜色渐变不断变换. 首先在main.xml文件中进行布局 总体布局为framelayout 中间有7个Textview,代表7种不同的颜色,可以看 ...
- android脚步---图片浏览
简单的图片浏览器,实现图像显示与点击切换下一张 首先在main.xml里面定义一个简单的线性布局容器. <?xml version="1.0" encoding=" ...
- ZUFE OJ 2301 GW I (3)
Description GW 是ZUFE的神犇,有一天他想到一种神奇的变换,并且将它命名为GW变换 对于一个数字n,该变换后的值GW(n)为,先令X=n 第一步,如果X为个位数,GW(n)=X,否则执 ...
- 关于有限状态机FSM同步复位的问题
FSM通常情况下使用异步信号进行复位,如FSM1中的rst_n信号.当rst_n信号为低时,FSM进入空闲状态IDLE. 在某些特殊情况下有可能需要跟随某个外部信号强制切换到空闲状态,也即同步复位.下 ...