CF

题意

有一个长度为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 动态开点线段树 或 离线的更多相关文章

  1. Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

    思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 els ...

  2. 【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) ...

  3. [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...

  4. codeforces 893F - Physical Education Lessons 动态开点线段树合并

    https://codeforces.com/contest/893/problem/F 题意: 给一个有根树, 多次查询,每次查询对于$x$i点的子树中,距离$x$小于等于$k$的所有点中权值最小的 ...

  5. HDU 6183 Color it(动态开点线段树)

    题目原网址:http://acm.hdu.edu.cn/showproblem.php?pid=6183 题目中文翻译: Time Limit: 20000/10000 MS (Java/Others ...

  6. [2016湖南长沙培训Day4][前鬼后鬼的守护 chen] (动态开点线段树+中位数 or 动规 or 贪心+堆优化)

    题目大意 给定一个长度为n的正整数序列,令修改一个数的代价为修改前后两个数的绝对值之差,求用最小代价将序列转换为不减序列. 其中,n满足小于500000,序列中的正整数小于10^9 题解(引自mzx神 ...

  7. 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

    4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss ...

  8. codeforces 915E - Physical Education Lessons 动态开点线段树

    题意: 最大$10^9$的区间, $3*10^5$次区间修改,每次操作后求整个区间的和 题解: 裸的动态开点线段树,计算清楚数据范围是关键... 经过尝试 $2*10^7$会$MLE$ $10^7$会 ...

  9. CF915E Physical Education Lessons 动态开点线段树

    题目链接 CF915E Physical Education Lessons 题解 动态开点线段树 代码 /* 动态开点线段树 */ #include<cstdio> #include&l ...

随机推荐

  1. 小白学python-day08-文件及其操作、字符串字典类型转换

    今天是day08,以下是学习总结: 但行努力,莫问前程. ----------------------------------------------------------------------- ...

  2. Kafka服务不可用(宕机)问题踩坑记

    背景 某线上日志收集服务报警,打开域名报502错误码. 收集服务由2台netty HA服务器组成,netty服务器将客户端投递来的protobuf日志解析并发送到kafka,打开其中一个应用的日志,发 ...

  3. Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)

    实践一下 Asp.Net Core (基于.net core 2.2)部署到Docker 一.准备工作: 1. 使用Virtualbox创建一个Centos系统的虚拟机,并安装docker和vim 2 ...

  4. [译]Python中的异步IO:一个完整的演练

    原文:Async IO in Python: A Complete Walkthrough 原文作者: Brad Solomon 原文发布时间:2019年1月16日 翻译:Tacey Wong 翻译时 ...

  5. 深入理解Apache Kafka

    一.介绍 Kafka在世界享有盛名,大部分互联网公司都在使用它,那么它到底是什么呢? Kafka由LinkedIn公司于2011年推出,自那时起功能逐步迭代,目前演变成一个完整的平台级产品,它允许您冗 ...

  6. WebService1

    一.什么是WebService(来源百度百科) Web service是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述. ...

  7. H5中的history方法Api介绍

    最近公司在做一个微信公众号,看了项目源码,看到项目中用到了history的Api来进行控制浏览器的历史记录及前进/后退键: 下面来跟大家一起来捋捋history的Api方法和使用: history.p ...

  8. 编程杂谈——Non-breaking space

    近日,意外地遇上件不寻常的事情.在解析PDF文件,读取其中内容的时候,对某一文件的处理,始终无法达到预期的效果. 解析方法如下: public void Parse(string value) { i ...

  9. 从输入URL到浏览器显示页面发生了哪些事情---个人理解

    经典面试题:从输入URL到页面显示发生了哪些事情 以前一直都记不住,这次自己理解了一下 用自己的话总结了一次,不对的地方希望大佬给我指出来 1.主机通过DHCP协议获取客户端的IP地址.子网掩码和DN ...

  10. 5 X 5 方阵引出的寻路算法 之 路径遍历(完结)

      此篇文章源自对一个有趣问题的思考,在我的另一篇博文<一个有趣的 5 X 5 方阵一笔画问题>中有详细介绍.在已知其结论的情况下,作为程序员的我,还是想利用该问题当做出发点,写一个可以遍 ...