其他分享
首页 > 其他分享> > [纪中D2A组T2/NOIP2013模拟联考2]公路维护(road)

[纪中D2A组T2/NOIP2013模拟联考2]公路维护(road)

作者:互联网

目录
[纪中D2A组T2/NOIP2013模拟联考2]公路维护(road)

题目

GMOJ3448
给定\(n\)个数,初始值均为\(I\),共\(m\)个操作:

  1. \(op=1\):检测区间是否有非正数,若无,区间全体减去一个数,\(ans=ans+1\)
  2. \(op=2\):给区间所有正数加上一个数
  3. \(op=3\):给定区间和一个值\(p\),遍历区间所有数\(a_i\),若\(0<a_i<p\),\(a_i=p\)

求结束时\(ans\)的值
\(n,m\le 10^5\)

思路

题目长这个样子明显是要我们用数据结构,操作又比较复杂,一般就用分块或线段树,我这里采用了线段树做法.
考虑我们要用线段树维护什么东西:因为有操作\(1\),我们首先要知道区间有没有非正数(损坏的路面),所以引进\(broken\)变量,与\(ask\_broken\)函数:(除\(build\)外所有函数传入的\(l,r\)都是指当前操作的区间)

//when building tree
broken[id]=false;

//ask_broken
		bool ask_broken(int p , int l , int r) {
			if(l <= tr[p].l && r >= tr[p].r)	return tr[p].broken;
			if(l > tr[p].r || r < tr[p].l)		return false;
#if LzyTag
			push_down(p);
#endif
			return ask_broken(ls(p) , l , r) || ask_broken(rs(p) , l , r);
			//ls/rs:	position of left/right son
		}
		

由于非正数(坏掉的路面)的值不会再升高,我们维护区间正数的最小值\(min\),由此,我们就能知道,每次进行区间减的操作时,是否会出现新的非正数,为了方便,对于全为非正数的区间,我们定义\(min=inf\),这样,我们就不用考虑后期对非正数\(min\)的特判.
弄完这些,才刚刚开始,毕竟懒标记才是线段树的精髓.
其实题目一共就两种区间修改操作:加上一个数(可以为负),区间的正数和一个数取\(\max\),因此,我们分别对操作定义两个懒标记\(tag_1,tag_2\),自己体会一下优先顺序,可以写出以下下传函数:

		inline void push_down(int x) {
			if(tr[x].tag1 != 0) {
				int add = tr[x].tag1;
				tr[ls(x)].tag1 += add;
				tr[ls(x)].tag2 += add;
				tr[ls(x)].min += add;
				
				tr[rs(x)].tag1 += add;
				tr[rs(x)].tag2 += add;
				tr[rs(x)].min += add;
				tr[x].tag1 = 0;
			}
			if(tr[x].tag2 > 0)
			{
				int val = tr[x].tag2;
				tr[ls(x)].tag2 = SegTree::max(val , tr[ls(x)].tag2);//注意这里是取较大值而不是直接赋值
				tr[ls(x)].min = SegTree::max(tr[ls(x)].min , val);
				
				tr[rs(x)].tag2 = SegTree::max(val , tr[rs(x)].tag2);
				tr[rs(x)].min = SegTree::max(tr[rs(x)].min , val);
				tr[x].tag2 = -inf;
			}
			
		}

两个修改对应的函数:
先说明:如果发现修改覆盖当前区间且\(min+val\le 0\)说明一定有新的损坏,虽然是区间全覆盖,但仍然要向下递归已更新\(min\)(别忘了是正数的最小值,若直接\(min=min+val\)就错了)和\(broken\).
每个点最多坏一次,坏一次就完整地向下递归一次,总次数不超过\(n\cdot \log n\),所以总复杂度依然没问题


		void change_add(int p , int l , int r , int val) {
//			if(tr[p].min > inf - 1e5)	return;
			if(tr[p].l > r || tr[p].r < l)	return;
			if(tr[p].l == tr[p].r) {
				tr[p].min += val;
				if(tr[p].min <= 0)
					tr[p].broken = true , tr[p].min = inf;
				return;
			}
#if LzyTag
			if(l <= tr[p].l && r >= tr[p].r) {
				if(tr[p].min + val <= 0) {
					push_down(p);
					change_add(ls(p) , l , r , val);
					change_add(rs(p) , l , r , val);
					tr[p].min = SegTree::min(tr[ls(p)].min , tr[rs(p)].min);
					tr[p].broken = tr[ls(p)].broken || tr[rs(p)].broken;
				}
				else {
					tr[p].min += val;
					tr[p].tag1 += val;
					tr[p].tag2 += val;
				}
				return ;
			}//*/
			push_down(p);
#endif
			change_add(ls(p) , l , r , val);
			change_add(rs(p) , l , r , val);
			tr[p].min = SegTree::min(tr[ls(p)].min , tr[rs(p)].min);
			tr[p].broken = tr[ls(p)].broken || tr[rs(p)].broken;
		}
		void change_ass(int p , int l , int r , int val) {
//			if(tr[p].min >= val)	return;
			if(tr[p].l > r || tr[p].r < l)	return;
			if(tr[p].l == tr[p].r) {
				if(tr[p].min < val)
					tr[p].min = val;
				return;
			}
#if LzyTag
			if(l <= tr[p].l && r >= tr[p].r ) {
				tr[p].min = SegTree::max(tr[p].min , val);
				tr[p].tag2 = SegTree::max(val , tr[p].tag2);
				return;
			}//*/
			push_down(p);
#endif
			change_ass(ls(p) , l , r , val);
			change_ass(rs(p) , l , r , val);
			tr[p].min = SegTree::min(tr[ls(p)].min , tr[rs(p)].min);
			tr[p].broken = tr[ls(p)].broken || tr[rs(p)].broken;
		}

code

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 100010
#define inf 0x3fffffff
#define reg register

#define DEBUG 0		//调试开关
#define LzyTag 1	//懒标记开关
int read() {
	int re = 0;
	char c = getchar();
	bool sig = false;
	while(c < '0' || c > '9')
		sig |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return sig ? -re : re;
}
int n , m , L;

class SegTree {
#define ls(_) tr[_].ls
#define rs(_) tr[_].rs

#if DEBUG
	public:
#else
	private:
#endif
		struct point {
			int l , r;//section:	[l,r]
			int ls , rs;//left son;	right son
			int min;
			bool broken;
#if LzyTag
			int tag1 , tag2;
			//tag1:		a += add
			//tag2:		a = max(a , p)
#endif
		} tr[N * 4];

		inline int min(int a , int b) {
			return a < b ? a : b;
		}
		inline int max(int a , int b) {
			return a > b ? a : b;
		}
		
		
#if LzyTag
		inline void push_down(int x) {
			if(tr[x].tag1 != 0) {
				int add = tr[x].tag1;
				tr[ls(x)].tag1 += add;
				tr[ls(x)].tag2 += add;
				tr[ls(x)].min += add;
				
				tr[rs(x)].tag1 += add;
				tr[rs(x)].tag2 += add;
				tr[rs(x)].min += add;
				tr[x].tag1 = 0;
			}
			if(tr[x].tag2 > 0)
			{
				int val = tr[x].tag2;
				tr[ls(x)].tag2 = SegTree::max(val , tr[ls(x)].tag2);
				tr[ls(x)].min = SegTree::max(tr[ls(x)].min , val);
				
				tr[rs(x)].tag2 = SegTree::max(val , tr[rs(x)].tag2);
				tr[rs(x)].min = SegTree::max(tr[rs(x)].min , val);
				tr[x].tag2 = -inf;
			}
			
		}
#endif

	public :
		int root;
		int build(int l , int r) {
			static int cnt = 0;
			int id = ++cnt;
			tr[id].l = l , tr[id].r = r , tr[id].broken = false , tr[id].min = L;

#if LzyTag
			tr[id].tag1 = 0 , tr[id].tag2 = -inf;
#endif
			if(l == r)
				return id;

			int mid = (l + r) / 2;
			ls(id) = build(l , mid);
			rs(id) = build(mid + 1 , r);
			return id;
		}
		void change_add(int p , int l , int r , int val) {
//			if(tr[p].min > inf - 1e5)	return;
			if(tr[p].l > r || tr[p].r < l)	return;
			if(tr[p].l == tr[p].r) {
				tr[p].min += val;
				if(tr[p].min <= 0)
					tr[p].broken = true , tr[p].min = inf;
				return;
			}
#if LzyTag
			if(l <= tr[p].l && r >= tr[p].r) {
				if(tr[p].min + val <= 0) {
					push_down(p);
					change_add(ls(p) , l , r , val);
					change_add(rs(p) , l , r , val);
					tr[p].min = SegTree::min(tr[ls(p)].min , tr[rs(p)].min);
					tr[p].broken = tr[ls(p)].broken || tr[rs(p)].broken;
				}
				else {
					tr[p].min += val;
					tr[p].tag1 += val;
					tr[p].tag2 += val;
				}
				return ;
			}//*/
			push_down(p);
#endif
			change_add(ls(p) , l , r , val);//renew
			change_add(rs(p) , l , r , val);
			tr[p].min = SegTree::min(tr[ls(p)].min , tr[rs(p)].min);
			tr[p].broken = tr[ls(p)].broken || tr[rs(p)].broken;
		}
		void change_ass(int p , int l , int r , int val) {
//			if(tr[p].min >= val)	return;
			if(tr[p].l > r || tr[p].r < l)	return;
			if(tr[p].l == tr[p].r) {
				if(tr[p].min < val)
					tr[p].min = val;
				return;
			}
#if LzyTag
			if(l <= tr[p].l && r >= tr[p].r ) {
				tr[p].min = SegTree::max(tr[p].min , val);
				tr[p].tag2 = SegTree::max(val , tr[p].tag2);
				return;
			}//*/
			push_down(p);
#endif
			change_ass(ls(p) , l , r , val);
			change_ass(rs(p) , l , r , val);
			tr[p].min = SegTree::min(tr[ls(p)].min , tr[rs(p)].min);
			tr[p].broken = tr[ls(p)].broken || tr[rs(p)].broken;
		}
		bool ask_broken(int p , int l , int r) {
			if(l <= tr[p].l && r >= tr[p].r)	return tr[p].broken;
			if(l > tr[p].r || r < tr[p].l)		return false;
#if LzyTag
			push_down(p);
#endif
			return ask_broken(ls(p) , l , r) || ask_broken(rs(p) , l , r);
		}
		
#if DEBUG && LzyTag
		int ask_min(int p , int pos) {
			if(tr[p].l == tr[p].r) {
				cout << (tr[p].min > 1e6 ? -1 : tr[p].min) << "\n";
				return 0;
			}
			push_down(p);
			int mid = (tr[p].l + tr[p].r) / 2;
			if(pos <= mid)	ask_min(ls(p) , pos);
			else			ask_min(rs(p) , pos);
		}
#endif

#undef ls
#undef rs
}segT;
int a[N];
int main() {
	freopen("road.in" , "r" , stdin);
	freopen("road.out" , "w" , stdout);
	n = read() , m =read() , L = read();
	segT.root = segT.build(1 , n);
	int ans = 0;
	
	for(int _ = 1 ; _ <= m ; _++) {
		int op = read() , s = read() , t = read() , val = read();
		bool pas;
		switch(op) {
			case 1:
#if DEBUG
//do something
#endif	
				pas = !segT.ask_broken(segT.root , s , t);
				if(!pas)	
					continue;
				++ans;
				segT.change_add(segT.root , s , t , -val);
				
				break;
			case 2:
				segT.change_add(segT.root , s , t , val);
				break;
			case 3:
				segT.change_ass(segT.root , s , t , val);
				break;
		}
	}
	cout << ans << '\n';
#if DEBUG
	for(int i = 1 ; i <= n ; i++)
		segT.ask_min(1 , i);
#endif
	return 0;
}

/*
5 4 2
2 2 5 2
1 5 5 3
3 4 5 5
3 1 5 4


10 7 3
1 2 6 4
2 3 3 3
3 8 10 4
3 3 10 3 //
3 2 7 3
2 5 10 2
1 1 5 4


10 6 2
3 3 7 3
3 8 9 2
1 1 6 1
1 5 10 1
1 1 2 1
1 5 7 1

10 11 2
3 6 9 1
3 1 5 5
3 3 7 5
2 7 8 2
2 7 7 1
3 8 9 3
2 8 10 4
3 1 5 3
1 5 6 3
3 1 3 1
1 5 9 1

*/

标签:NOIP2013,val,min,int,rs,tr,纪中,ls,联考
来源: https://www.cnblogs.com/dream1024/p/15013743.html