HDU5367 思维map // 动态线段树
地主毛毛有n座山,这些山在地主家门前排成一条直线。这些山一开始均有相同的高度。 每一天,毛毛都会要求花花开挖机把几座山挖掉一定高度,或者给一些山堆上一些高度。并且要求花花报告现在有多少座山属于“高山脉”当一排山的高度相等,并且比这排山左边和右边的山要高时,这排山被称为高山脉。当然,最左边和最右边的山不可能是“高山脉”的一部分
这题乍一看可以用线段树做,事实上确实可以用线段树做,但是在仔细思考,讨论出所有情况之后发现可以修改端点代替修改区间的方法来AC
也就是说,将每次修改的L和R变为修改单点,用一次solve来将L之后的所有山全部加上v,再用一次solve来将R + 1之后的山高度全部减去R,在修改的过程中利用map来修改ans可以实现题目要求的在线
1.map的AC代码
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
#define For(i, x, y) for(int i=x; i<=y; i++)
#define _For(i, x, y) for(int i=x; i>=y; i--)
#define Mem(f, x) memset(f, x, sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i = 0; i <= N ; i ++) u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
inline int read()
{
int now=;register char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());
return now;
}
int N,Q,R;
int ans = ;
map<int,int>P;
void solve(int mid,int v){
if(!v)return;
map<int,int> ::iterator it,l,r;
//cout << mid << " " << P[mid] <<endl;
if(P[mid] == ){
l = r = it = P.find(mid); //这一步要放在if里面
l--,r++;
if(l->se > && r->se > && v < ){
ans += (mid - l->fi);
// cout << l->fi << " " << it->fi << " " << r->fi << endl;
}else if(l->se > && r->se < && v < ){
ans -= (r->fi - mid);
}else if(l->se < && r->se < && v > ){
ans += (r->fi - mid);
}else if(l->se > && r->se < && v > ){
ans -= mid - l->fi;
}
P[mid] = v;
}else{
l = r = it = P.find(mid);
l--,r++;
if(r == P.end() || it == P.begin()) return; //对最左端和最右端的更新
if(l->se > && r->se > && it->se < ){
ans -= mid - l->fi;
}else if(l->se < && r->se < && it->se > ){
ans -= r->fi - mid;
}else if(l->se > && r->se < && it->se < ){
ans += r->fi - mid;
}else if(l->se > && r->se < && it->se > ){
ans += mid - l->fi;
}
// cout << it->fi << " " << it->se << endl;
v += it->se;
P.erase(it);
solve(mid,v);
}
}
int main()
{
while(~scanf("%d%d%d",&N,&Q,&R)){
P.clear();
P[] = -INF; P[N + ] = INF;
ans = ;
while(Q--){
int l,r,v;
scanf("%d%d%d",&l,&r,&v);
l ^= ans; r ^= ans; v ^= ans;
solve(l,v);
solve(r + ,-v);
Pri(ans);
}
}
return ;
}
2.有了以上的算法,从实现难度上来讲线段树就不算是最优解了,但是对练习线段树的写法也有一定意义,所以我用线段树也实现了一次。
由于N大到1e9次,就不能像普通线段树一样直接build建树,要通过动态加点,也就是说只开辟使用到的区间的空间,由于查询只有50000次,仅仅开辟使用的空间并不会导致mle,学习了一手动态线段树的写法,这就很舒服
这次线段树的难度主要在于pushup的实现上已经怎么想到维护的点,去维护什么东西,还有动态线段树的实现
以下是动态线段树的代码
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
#define For(i, x, y) for(int i=x; i<=y; i++)
#define _For(i, x, y) for(int i=x; i>=y; i--)
#define Mem(f, x) memset(f, x, sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i = 0; i <= N ; i ++) u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
inline int read()
{
int now=;register char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());
return now;
}
int ans;
int N,Q,R;
struct Tree{
int lt,rt;
int sum; //高山脉的数目
int lsum,rsum; //左右起高度相同的山脉
int lh,rh; //左右山脉的高度
int ll,rr; //左右第一个不连续山脉的高度
int lazy;
void init(int l,int r){
sum = lh = rh = ll = rr = lazy = lt = rt = ;
lsum = rsum = r - l + ;
}
}tree[maxn * ];
int tot;
void check(int &t,int l,int r){
if(t) return;
t = ++tot;
tree[t].init(l,r);
if(l == ) tree[t].ll = INF;
if(r == N) tree[t].rr = INF;
}
void add(int t,int val){
tree[t].lazy += val;
tree[t].ll += val; tree[t].rr += val;
tree[t].lh += val; tree[t].rh += val;
}
void Pushdown(int t,int l,int r){
if(tree[t].lazy){
int m = (l + r) >> ;
check(tree[t].lt,l,m);
check(tree[t].rt,m + ,r);
add(tree[t].rt,tree[t].lazy);
add(tree[t].lt,tree[t].lazy);
tree[t].lazy = ;
}
}
void Pushup(int t,int l,int r){
int m = (l + r) >> ;
int lt = tree[t].lt;
int rt = tree[t].rt;
check(lt,l,m); check(rt,m + ,r);
tree[t].sum = tree[lt].sum + tree[rt].sum;
tree[t].lsum = tree[lt].lsum; tree[t].rsum = tree[rt].rsum;
tree[t].lh = tree[lt].lh; tree[t].rh = tree[rt].rh;
tree[t].ll = tree[lt].ll; tree[t].rr = tree[rt].rr;
if(tree[lt].rh == tree[rt].lh){
if(tree[lt].rh > tree[lt].rr && tree[rt].ll < tree[rt].lh){
tree[t].sum += tree[lt].rsum + tree[rt].lsum;
}
if(tree[lt].rsum == m - l + ){
tree[t].lsum += tree[rt].lsum;
tree[t].ll = tree[rt].ll;
}
if(tree[rt].lsum == r - m){
tree[t].rsum += tree[lt].rsum;
tree[t].rr = tree[lt].rr;
}
}else{
int lson = lt; int rson = rt;
if(tree[lson].lsum == m - l + ){
tree[t].ll = tree[rson].lh;
}
if(tree[lson].rh > tree[rson].lh && tree[lson].rh > tree[lson].rr){
tree[t].sum += tree[lson].rsum;
}
if(tree[rson].rsum == r - m){
tree[t].rr = tree[lson].rh;
}
if(tree[rson].lh > tree[lson].rh && tree[rson].lh > tree[rson].ll){
tree[t].sum += tree[rson].lsum;
}
}
}
void update(int &t,int l,int r,int L,int R,int val){
check(t,l,r);
if(L <= l && r <= R){
add(t,val);
return;
}
Pushdown(t,l,r);
int m = (l + r) >> ;
if(L <= m) update(tree[t].lt,l,m,L,R,val);
if(R > m) update(tree[t].rt,m + ,r,L,R,val);
Pushup(t,l,r);
}
int main()
{
while(~scanf("%d%d%d",&N,&Q,&R)){
ans = ;
tot = ;
int root = ;
while(Q--){
int l,r,val;
scanf("%d%d%d",&l,&r,&val);
l ^= ans; r ^= ans; val ^= ans;
if(l > r) swap(l,r);
update(root,,N,l,r,val);
ans = tree[root].sum;
Pri(ans);
}
}
return ;
}
HDU5367 思维map // 动态线段树的更多相关文章
- HDU1199 动态线段树 // 离散化
附动态线段树AC代码 http://acm.hdu.edu.cn/showproblem.php?pid=1199 因为昨天做了一道动态线段树的缘故,今天遇到了这题没有限制范围的题就自然而然想到了动态 ...
- C. Okabe and Boxes 思维 模拟 or 线段树
C. Okabe and Boxes 这个题目是一个有点思维的模拟,当时没有想到, 思维就是这个栈的排序这里,因为每次直接排序肯定会t的,所以不可以这么写,那怎么表示排序呢? 就是直接把栈清空,如果栈 ...
- CF666E Forensic Examination(后缀自动机+动态线段树)
题意 给你一个串 $S$ 以及一个字符串数组 $T[1..m]$ , $q$ 次询问,每次问 $S$ 的子串 $S[p_l..p_r]$ 在 $T[l..r]$ 中的哪个串里的出现次数最多,并输出出现 ...
- Codeforces 916E(思维+dfs序+线段树+LCA)
题面 传送门 题目大意:给定初始根节点为1的树,有3种操作 1.把根节点更换为r 2.将包含u,v的节点的最小子树(即lca(u,v)的子树)所有节点的值+x 3.查询v及其子树的值之和 分析 看到批 ...
- BZOJ3531 树剖 + 动态开点线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=3531 首先这题意要求树链上的最大值以及求和,其树链剖分的做法已经昭然若揭 问题在于这次的信息有宗教 ...
- 线段树动态开点——cf1045G
只计算半径小的能看到的半径大的,因为如果计算半径大的看到半径小的,虽然q在其范围内,但是小的不一定能看到大的 那么我们将机器人按照半径降序排序 遍历一次,去查询在[x-r,x+r]范围的,智商在[q- ...
- dfs+线段树 zhrt的数据结构课
zhrt的数据结构课 这个题目我觉得是一个有一点点思维的dfs+线段树 虽然说看起来可以用树链剖分写,但是这个题目时间卡了树剖 因为之前用树剖一直在写这个,所以一直想的是区间更新,想dfs+线段树,有 ...
- NBUT 1120 线段树
input q n q行 F a b或者Q a b output face left face top face right 可以用map或者线段树做 //map #include<cstdio ...
- CodeForces 19D Points (线段树+set)
D. Points time limit per test 2 seconds memory limit per test 256 megabytes input standard input out ...
随机推荐
- 12.16 Daily Scrum
Today's Task Tomorrow's Task 丁辛 实现和菜谱相关的餐厅列表. 实现和菜谱相关的餐厅列表. 邓亚梅 美化搜索框UI. 美 ...
- 《Linux内核分析》课程第七周学习总结
姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- Linux内核设计与实现 第四章
1. 什么是调度 现在的操作系统都是多任务的,为了能让更多的任务能同时在系统上更好的运行,需要一个管理程序来管理计算机上同时运行的各个任务(也就是进程). 这个管理程序就是调度程序,功能: 决定哪些进 ...
- win10装MySQL5.7
越来越发现装MySQL很费劲啊,装了N次,都很懵逼,找对的解决方案很重要. Mysql5.7下载地址:http://xiazai.zol.com.cn/detail/4/33431.shtml 安装步 ...
- octave基本指令1
octave基本指令1 注释 使用: disp 输出指令 eg: >>a = pi; >>disp(sprintf('2 decimals:%0.2f'a)) 2 decima ...
- Minify or format javascript file by web or notepad++
Notepad++ plugin manager install 'JSTOOL' http://tool.oschina.net/codeformat/js https://www.cnblogs. ...
- Jfrog Artifactory 创建docker 镜像仓库以及 push 镜像到 该仓库.
1. 安装aitifactory 以及 启动 使用30天有效期激活 不在阐述. 2. 登录artifactory username:admin password:password 3. 创建 仓库 在 ...
- [转帖]git、github、gitlab之间的关系
Git - 版本控制工具 Github - 一个网站,提供给用户空间创建git仓储,保存用户的一些数据文档或者代码等 GitLab - 基于Git的项目管理软件 Git分布式版本控制系统 Git是一款 ...
- 小项目分析之C++ 实现模拟银行排队
一.问题定义与分析 问题定义 •要解决的问题——银行一天之内的: 1.总客户数 2.客户总逗留时间 3.客户平均逗留时间 问题分析 •新来的人找个短的队伍,站在队尾开始排队 •排在队头的人可以办理 ...
- Lodop打印控件里SET_PRINT_STYLE和SET_PRINT_STYLEA
LODOP.SET_PRINT_STYLE 对该语句后面的打印项样式设置效果.LODOP.SET_PRINT_STYLEA 针对第一个参数设置的打印项样式设置效果.这两个语句,作用范围不同. 在设置字 ...