CF803G - Periodic RMQ Problem 动态开点线段树 或 离线
题意
有一个长度为n × k (<=1E9)的数组,有区间修改和区间查询最小值的操作。
思路
由于数组过大,直接做显然不行。
有两种做法,可以用动态开点版本的线段树,或者离线搞(还没搞)(搞好了)。
注意只有1E5次操作,所以真正被更新到的区间并不多,最差单次新开2×log(1E9)。
对于新开的区间的最小值,可以这样计算,如果区间表示的值大于n,那就是原来长度为n的区间的最小值,小于n的话,在ST表中查询即可。
- #include <bits/stdc++.h>
- using namespace std;
- #define pb push_back
- #define fi first
- #define se second
- #define debug(x) cerr<<#x << " := " << x << endl;
- #define bug cerr<<"-----------------------"<<endl;
- #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
- typedef long long ll;
- typedef long double ld;
- typedef pair<int, int> pii;
- typedef pair<ll, ll> pll;
- template<class T> void _R(T &x) { cin >> x; }
- void _R(int &x) { scanf("%d", &x); }
- void _R(ll &x) { scanf("%lld", &x); }
- void _R(double &x) { scanf("%lf", &x); }
- void _R(char &x) { scanf(" %c", &x); }
- void _R(char *x) { scanf("%s", x); }
- void R() {}
- template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); }
- template<typename T>
- inline T read(T&x){
- x=;int f=;char ch=getchar();
- while (ch<''||ch>'') f|=(ch=='-'),ch=getchar();
- while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
- return x=f?-x:x;
- }
- const int inf = 0x3f3f3f3f;
- const int mod = 1e9+;
- /**********showtime************/
- const int maxn = 1e5+;
- int b[maxn];
- int st[maxn][], Log[maxn];
- void init_st(int n) {
- Log[] = -;
- for(int i=; i<=n; i++) {
- Log[i] = Log[i>>] + ;
- st[i][] = b[i];
- }
- for(int j=; (<<j) <= n; j++) {
- for(int i=; i + (<<j) - <= n; i++) {
- st[i][j] = min(st[i][j-], st[i+ (<<(j-))][j-]);
- }
- }
- }
- int rmq_st(int L, int R) {
- int k = Log[R - L + ];
- return min(st[L][k], st[R-(<<k)+][k]);
- }
- int n,k;
- int getmin(int le, int ri) {
- if(ri - le + >= n) return rmq_st(, n);
- int L = le % n; if(L == ) L = n;
- int R = ri % n; if(R == ) R = n;
- if(L <= R) return rmq_st(L, R);
- return min(rmq_st(L, n), rmq_st(, R));
- }
- struct Node{
- int le, ri;
- int lc,rc;
- int val, tag;
- } tree[maxn * ];
- int tot = ;
- int newNode(int le, int ri) {
- tot++;
- tree[tot].le = le;
- tree[tot].ri = ri;
- tree[tot].lc = tree[tot].rc = ;
- tree[tot].val = getmin(le, ri);
- tree[tot].tag = ;
- return tot;
- }
- void pushdown(int rt) {
- tree[tree[rt].lc].val = tree[tree[rt].lc].tag = tree[rt].tag;
- tree[tree[rt].rc].val = tree[tree[rt].rc].tag = tree[rt].tag;
- tree[rt].tag = ;
- }
- void update(int L, int R, int b, int rt) {
- if(L<=tree[rt].le && tree[rt].ri <= R) {
- tree[rt].val = tree[rt].tag = b;
- return;
- }
- int mid = (tree[rt].le + tree[rt].ri) >> ;
- if(tree[rt].lc == ) tree[rt].lc = newNode(tree[rt].le, mid);
- if(tree[rt].rc == ) tree[rt].rc = newNode(mid+, tree[rt].ri);
- if(tree[rt].tag) pushdown(rt);
- if(mid >= L) update(L, R, b, tree[rt].lc);
- if(mid < R) update(L, R, b, tree[rt].rc);
- tree[rt].val = min(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
- }
- int query(int L, int R, int rt) {
- if(L <= tree[rt].le && tree[rt].ri <= R) {
- return tree[rt].val;
- }
- int mid = (tree[rt].le + tree[rt].ri) >> ;
- if(tree[rt].lc == ) tree[rt].lc = newNode(tree[rt].le, mid);
- if(tree[rt].rc == ) tree[rt].rc = newNode(mid+, tree[rt].ri);
- if(tree[rt].tag) pushdown(rt);
- int res = inf;
- if(mid >= L) res = min(res, query(L, R, tree[rt].lc));
- if(mid < R) res = min(res, query(L, R, tree[rt].rc));
- tree[rt].val = min(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
- return res;
- }
- int main(){
- scanf("%d%d", &n, &k);
- for(int i=; i<=n; i++) scanf("%d", &b[i]);
- init_st(n);
- int q; scanf("%d", &q);
- newNode(, n * k);
- while(q--) {
- int op;
- scanf("%d", &op);
- if(op == ) {
- int le,ri,x;
- scanf("%d%d%d", &le, &ri, &x);
- update(le, ri, x, );
- }
- else {
- int le, ri;
- scanf("%d%d", &le, &ri);
- printf("%d\n", query(le, ri, ));
- }
- }
- return ;
- }
离线的话,我们可以记录下所有被问到的点,然后我们可以压缩原来长度为1E9的数组:问到的点保持不变,而相邻两点之间的区间压缩成一个点,保存这段区间的最小值即可。
- #include <iostream>
- #include <vector>
- #include <queue>
- #include <algorithm>
- using namespace std;
- #define pb push_back
- #define fi first
- #define se second
- #define debug(x) cerr<<#x << " := " << x << endl;
- #define bug cerr<<"-----------------------"<<endl;
- #define FOR(a, b, c) for(int a = b; a <= c; ++ a)
- typedef long long ll;
- typedef long double ld;
- typedef pair<int, int> pii;
- typedef pair<ll, ll> pll;
- template<class T> void _R(T &x) { cin >> x; }
- void _R(int &x) { scanf("%d", &x); }
- void _R(ll &x) { scanf("%lld", &x); }
- void _R(double &x) { scanf("%lf", &x); }
- void _R(char &x) { scanf(" %c", &x); }
- void _R(char *x) { scanf("%s", x); }
- void R() {}
- template<class T, class... U> void R(T &head, U &... tail) { _R(head); R(tail...); }
- template<typename T>
- inline T read(T&x){
- x=;int f=;char ch=getchar();
- while (ch<''||ch>'') f|=(ch=='-'),ch=getchar();
- while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
- return x=f?-x:x;
- }
- const int inf = 0x3f3f3f3f;
- const int mod = 1e9+;
- /**********showtime************/
- const int maxn = 1e5+;
- int b[maxn];
- struct Query{
- int op;
- int le,ri;
- int x;
- } ask[maxn];
- vector<int>v, nv,node;
- int n,k;
- int st[maxn][];
- int Log[maxn];
- void init_st(int n){
- Log[] = -;
- for(int i = ; i<=n; i++) {
- st[i][] = b[i];
- Log[i] = Log[i>>] + ;
- }
- for(int j=; (<<j) <= n; j++) {
- for(int i=; i + ( << j) - <= n; i ++) {
- st[i][j] = min(st[i][j-], st[i + (<<(j-)) ][j-]);
- }
- }
- }
- int get(int L, int R) {
- int k = Log[R - L + ];
- return min(st[L][k], st[R-(<<k)+][k]);
- }
- int getmin(int le, int ri) {
- if(ri - le + >= n)
- return get(, n);
- int l = le % n; if(!l) l = n;
- int r = ri % n; if(!r) r = n;
- if(l <= r) return get(l, r);
- return min(get(l, n), get(, r));
- }
- int getid(int val) {
- return lower_bound(nv.begin(), nv.end(), val) - nv.begin() + ;
- }
- int mn[maxn*],lazy[maxn * ];
- void build(int le, int ri, int rt) {
- if(le == ri) {
- mn[rt] = node[le-];
- return;
- }
- int mid = (le + ri) >> ;
- build(le, mid, rt<<);
- build(mid+, ri, rt<<|);
- mn[rt] = min(mn[rt<<], mn[rt<<|]);
- }
- void pushdown(int rt) {
- mn[rt<<] = mn[rt<<|] = lazy[rt];
- lazy[rt<<] = lazy[rt<<|] = lazy[rt];
- lazy[rt] = ;
- }
- void update(int L, int R,int x, int le, int ri, int rt) {
- if(le >= L && ri <= R){
- lazy[rt] = x;
- mn[rt] = x;
- return ;
- }
- if(lazy[rt]) pushdown(rt);
- int mid = (le + ri) >> ;
- if(mid >= L) update(L, R, x, le, mid, rt<<);
- if(mid < R) update(L, R, x, mid+, ri, rt<<|);
- mn[rt] = min(mn[rt<<], mn[rt<<|]);
- }
- int query(int L, int R,int le, int ri, int rt) {
- if(le >= L && ri <= R) {
- return mn[rt];
- }
- if(lazy[rt]) pushdown(rt);
- int mid = (le + ri) >> ;
- int res = inf;
- if(mid >= L) res = min(res, query(L, R, le, mid, rt<<));
- if(mid < R) res = min(res, query(L, R, mid+,ri, rt<<|));
- mn[rt] = min(mn[rt<<], mn[rt<<|]);
- return res;
- }
- int main(){
- scanf("%d%d", &n, &k);
- for(int i=; i<=n; i++) scanf("%d", &b[i]);
- init_st(n);
- int q; scanf("%d", &q);
- for(int i=; i<=q; i++){
- int op;
- scanf("%d", &op);
- if(op == ) {
- ask[i].op = op;
- scanf("%d%d%d", &ask[i].le, &ask[i].ri, &ask[i].x);
- v.pb(ask[i].le);
- v.pb(ask[i].ri);
- }
- else{
- ask[i].op = op;
- scanf("%d%d", &ask[i].le, &ask[i].ri);
- v.pb(ask[i].le);
- v.pb(ask[i].ri);
- }
- }
- sort(v.begin(), v.end());
- v.erase(unique(v.begin(), v.end()), v.end());
- int N = v.size();
- // cout<<" ** "<<endl;
- for(int i=; i<N; i++) {
- node.pb( getmin(v[i],v[i]));
- nv.pb(v[i]);
- if(i+ < N && v[i] + <= v[i+] - )
- {
- node.pb(getmin(v[i]+, v[i+]-));
- nv.pb(v[i]+);
- }
- }
- /// 把一个开区间当成一个点。
- N = nv.size();
- build(, N, );
- for(int i=; i<=q; i++) {
- if(ask[i].op == ) {
- update(getid(ask[i].le),getid(ask[i].ri), ask[i].x, , N, );
- }
- else {
- printf("%d\n",query(getid(ask[i].le), getid(ask[i].ri), , N, ));
- }
- }
- return ;
- }
CF803G - Periodic RMQ Problem 动态开点线段树 或 离线的更多相关文章
- Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树
思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用 lazy=0 没被覆盖过 els ...
- 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树
题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...
- [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...
- codeforces 893F - Physical Education Lessons 动态开点线段树合并
https://codeforces.com/contest/893/problem/F 题意: 给一个有根树, 多次查询,每次查询对于$x$i点的子树中,距离$x$小于等于$k$的所有点中权值最小的 ...
- HDU 6183 Color it(动态开点线段树)
题目原网址:http://acm.hdu.edu.cn/showproblem.php?pid=6183 题目中文翻译: Time Limit: 20000/10000 MS (Java/Others ...
- [2016湖南长沙培训Day4][前鬼后鬼的守护 chen] (动态开点线段树+中位数 or 动规 or 贪心+堆优化)
题目大意 给定一个长度为n的正整数序列,令修改一个数的代价为修改前后两个数的绝对值之差,求用最小代价将序列转换为不减序列. 其中,n满足小于500000,序列中的正整数小于10^9 题解(引自mzx神 ...
- 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化
4636: 蒟蒻的数列 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 247 Solved: 113[Submit][Status][Discuss ...
- codeforces 915E - Physical Education Lessons 动态开点线段树
题意: 最大$10^9$的区间, $3*10^5$次区间修改,每次操作后求整个区间的和 题解: 裸的动态开点线段树,计算清楚数据范围是关键... 经过尝试 $2*10^7$会$MLE$ $10^7$会 ...
- CF915E Physical Education Lessons 动态开点线段树
题目链接 CF915E Physical Education Lessons 题解 动态开点线段树 代码 /* 动态开点线段树 */ #include<cstdio> #include&l ...
随机推荐
- 异常处理 _this.setData is not a function
_this.setData is not a function;at api request success callback function TypeError: _this.setData is ...
- abp(net core)+easyui+efcore实现仓储管理系统——使用 WEBAPI实现CURD (十二)
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...
- 集合(Collection解析 Set List Map三大集合运用)
集合的概念: 集合是包含多个对象的简单对象,所包含的对象称为元素.集合里面可以包含任意多个对象,数量可以变化:同时对对象的类型也没有限制,也就是说集合里面的所有对象的类型可以相同,也 ...
- [ PyQt入门教程 ] PyQt5基本控件使用:消息弹出、用户输入、文件对话框
本文主要介绍PyQt界面实现中常用的消息弹出对话框.提供用户输入的输入框.打开文件获取文件/目录路径的文件对话框.学习这三种控件前,先想一下它们使用的主要场景: 1.消息弹出对话框.程序遇到问题需要退 ...
- 自定义 EditText 样式
极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以 ...
- Selenium+java - 借助autolt完成上传文件操作
写在前面: 上传文件是每个自动化测试同学会遇到,而且可以说是面试必考的问题,标准控件我们一般用sendkeys()就能完成上传,但是我们的测试网站的上传控件一般为自己封装的,用传统的上传已经不好用了, ...
- 已知词频生成词云图(数据库到生成词云)--generate_from_frequencies(WordCloud)
词云图是根据词出现的频率生成词云,词的字体大小表现了其频率大小. 写在前面: 用wc.generate(text)直接生成词频的方法使用很多,所以不再赘述. 但是对于根据generate_from_f ...
- MobaXterm:远程终端登录软件封神选手
提到SSH.Telnet等远程终端登录,我相信很多人想到的都是PuTTY PuTTY通常用于Windows,但实际上可以多平台运行,因此不表达为"Windows下的远程终端登录" ...
- C#的委托事件总结
什么是委托?1.委托是C#中由用户自定义的一个类型.2.类表示的是数据和方法的集合,而委托实际上是一个能持有对某个或某些方法的引用的类.3.与其他的类不同,委托类能拥有一个签名,并且他只能持有与他的签 ...
- ibatis 核心原理解析
最近查找一个生产问题的原因,需要深入研究 ibatis 框架的源码.虽然最后证明问题的原因与 ibatis 无关,但是这个过程加深了对 ibatis 框架原理的理解. 这篇文章主要就来讲讲 ibati ...