探险
探险
(explore.pas/c/cpp)
【题目描述】
小林和亮亮来到森林中探险,森林中有一条长度为 S 的小路(编号从 1 到 S),且在小路上时常会起雾,亮亮也可以用神光让雾消散。
小林则关心在某一位置的视野。若位置 x 有浓雾,则位置 x 的视野为 0。若从 x 一直到 S 或从 x 一直到 1 全都没有浓雾,则视野为 INF。其他情况下,位置x 的 视 野 定 义 为 max{ L-R +1 }, 其 中 L, R 满 足 : L ≤ x ≤ R ,"x∈{A∈N|L≤A≤R},格子没有浓雾 。
具体来说,会有以下事件发生:
1、“1 L R”小路的[L, R]部分产生了浓雾;
2、“2 L R”小路的[L, R]部分浓雾散去了。
3、“3 X” 查询 X 点的视野。
一开始,小路上没有任何浓雾。
【输入格式】
第一行一个整数,为小路的长度 S。
第二行一个整数,为事件数 Q。
接下来 Q 行,每行一个事件,格式如题目描述。
【输出格式】
对于每一个询问事件,输出一个整数或一行字符串“INF”,代表所求视野。
【样例输入】
5
5
1 2 4
3 1
3 4
2 3 3
3 3
【样例输出】
INF
0
1
【数据规模】
对于 40%的数据, S*Q <= 5*10^7。
对于 100%的数据, 2≤S≤100,000,2≤Q≤200,000, 1≤L≤R≤S, 1≤X≤S。
【问题分析】
线段树,这一题需要用到lazy_tag,就是标记法打线段树。
线段树每个结点记录两个值lzy和now(0或1表示是否有浓雾),1表示当前结点能够有浓雾,一个结点没有浓雾当且仅当他的左孩子和右孩子都没有浓雾。
Lzy用来记录改变值,就是当前结点要变成什么样的状态,用到这个结点时把now变为lzy,并且更新孩子时要把lzy下放,下放之后当前节点lzy变为-1,表示当前节点没有lzy,没有lzy就不下放,孩子还是原来的值。Lzy最大的作用就是节省更新的时间,不必要每个点的去更新,当然也有很多线段树的题不需要用lzy。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 const int N = 200009; 5 struct Node 6 { 7 int lzy, now; 8 }t[4*N]; 9 int n, m; 10 void pushdown(int rt, int lc, int rc) 11 { 12 if(t[rt].lzy == -1) return; 13 t[lc].lzy = t[rt].lzy; 14 t[lc].now = t[lc].lzy; 15 t[rc].lzy = t[rt].lzy; 16 t[rc].now = t[rc].lzy; 17 t[rt].lzy = -1; 18 return; 19 } 20 void update(int l, int r, int rt, int L, int R, int tag) 21 { 22 if(l > r || r < L || l > R) return; 23 if(L <= l && r <= R) 24 { 25 t[rt].now = tag; 26 t[rt].lzy = tag; 27 return; 28 } 29 int mid = (l + r) >> 1; 30 int lc = rt << 1; 31 int rc = rt << 1 | 1; 32 pushdown(rt, lc, rc); 33 update(l, mid, lc, L, R, tag); 34 update(mid+1, r, rc, L, R, tag); 35 t[rt].now = (t[lc].now | t[rc].now); 36 } 37 int query(int l, int r, int rt, int L, int R) 38 { 39 if(l > r || r < L || l > R) return 0; 40 if(L <= l && r <= R) return t[rt].now; 41 int mid = (l + r) >> 1; 42 int lc = rt << 1; 43 int rc = rt << 1 | 1; 44 pushdown(rt, lc, rc); 45 int ltag = query(l, mid, lc, L, R); 46 int rtag = query(mid+1, r, rc, L, R); 47 t[rt].now = (t[lc].now | t[rc].now); 48 if(R <= mid) return ltag; 49 if(mid < L) return rtag; 50 return (ltag | rtag); 51 } 52 int main() 53 { 54 freopen("explore.in", "r", stdin); 55 freopen("explore.out", "w", stdout); 56 scanf("%d%d", &n, &m); 57 for(int i = 1; i <= m; i++) 58 { 59 int v; 60 scanf("%d", &v); 61 if(v == 1) 62 { 63 int l, r; 64 scanf("%d%d", &l, &r); 65 update(1, n, 1, l, r, 1); 66 } 67 if(v == 2) 68 { 69 int l, r; 70 scanf("%d%d", &l, &r); 71 update(1, n, 1, l, r, 0); 72 } 73 if(v == 3) 74 { 75 int x; 76 scanf("%d", &x); 77 int xtag = query(1, n, 1, x, x); 78 if(xtag) 79 { 80 puts("0"); 81 continue; 82 } 83 int ltag = query(1, n, 1, 1, x); 84 if(!ltag) 85 { 86 puts("INF"); 87 continue; 88 } 89 int rtag = query(1, n, 1, x, n); 90 if(!rtag) 91 { 92 puts("INF"); 93 continue; 94 } 95 int l = 1, r = x, Ll = x, Rl = x; 96 while(l <= r) 97 { 98 int mid = (l + r) >> 1; 99 int vtag = query(1, n, 1, mid, x); 100 if(!vtag) 101 Ll = mid, r = mid - 1; 102 else l = mid + 1; 103 } 104 l = x; r = n; 105 while(l <= r) 106 { 107 int mid = (l + r) >> 1; 108 int vtag = query(1, n, 1, x, mid); 109 if(!vtag) 110 Rl = mid, l = mid + 1; 111 else r = mid - 1; 112 } 113 printf("%d\n", Rl - Ll + 1); 114 } 115 } 116 return 0; 117 }