求点所在的最长连续区间
http://acm.hdu.edu.cn/showproblem.php?pid=1540
Tunnel Warfare
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 18628 Accepted Submission(s): 7171
Problem Description
During
the War of Resistance Against Japan, tunnel warfare was carried out
extensively in the vast areas of north China Plain. Generally speaking,
villages connected by tunnels lay in a line. Except the two at the ends,
every village was directly connected with two neighboring ones.
Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
Input
The
first line of the input contains two positive integers n and m (n, m ≤
50,000) indicating the number of villages and events. Each of the next m
lines describes an event.
There are three different events described in different format shown below:
D x: The x-th village was destroyed.
Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.
R: The village destroyed last was rebuilt.
There are three different events described in different format shown below:
D x: The x-th village was destroyed.
Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.
R: The village destroyed last was rebuilt.
Output
Output the answer to each of the Army commanders’ request in order on a separate line.
Sample Input
7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
Sample Output
1
0
2
4
Source
Recommend
LL
题意:n个村庄,m次操作,有三种操作,1、D摧毁该村庄,2、R恢复上一个被摧毁的村庄,3、Q询问该点两边最大未摧毁的村庄之和。
解法:用栈储存被摧毁的村庄,线段树维护两个值ma,mi最大值与最小值。
初始更新ma为0 , mi 为n+1.
摧毁更新ma为x,mi为x
询问x , 询问1-x的最大值max,询问右边x-n的最小值min , 结果为min- max - 1.
https://blog.csdn.net/chudongfang2015/article/details/52133243
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SF(n) scanf("%d" , &n) #define rep(i , n) for(int i = 0 ; i < n ; i ++) #define INF 0x3f3f3f3f #define mod 20191117 #define PI acos(-1) using namespace std; typedef long long ll ; int n , q ; char s[10]; int ma , mi; struct node { int l , r , ma , mi ; }tree[500009*4]; void build(int l , int r , int root) { tree[root].l = l , tree[root].r = r ; if(l == r) { tree[root].ma = 0 ; tree[root].mi = n + 1; return ; } int mid = (l + r) >> 1; build(l , mid , root*2); build(mid+1 , r , root*2+1); tree[root].ma = max(tree[root*2].ma , tree[root*2+1].ma); tree[root].mi = min(tree[root*2].mi , tree[root*2+1].mi); } void update_max(int x , int val , int root) { if(tree[root].l == tree[root].r) { tree[root].ma = val ; return ; } int mid = (tree[root].l + tree[root].r) >> 1 ; if(x <= mid) update_max(x , val , root*2); else update_max(x , val , root*2+1); tree[root].ma = max(tree[root*2].ma , tree[root*2+1].ma); } void update_min(int x , int val , int root) { if(tree[root].l == tree[root].r) { tree[root].mi = val ; return ; } int mid = (tree[root].l + tree[root].r) >> 1 ; if(x <= mid) update_min(x , val , root*2); else update_min(x , val , root*2+1); tree[root].mi = min(tree[root*2].mi , tree[root*2+1].mi); } void query_max(int l , int r , int root) { if(tree[root].l >= l && tree[root].r <= r) { ma = max(tree[root].ma , ma); return ; } int mid = (tree[root].l + tree[root].r) >> 1 ; if(l <= mid) query_max(l , r , root*2); if(r > mid) query_max(l , r, root*2+1); } void query_min(int l , int r , int root) { if(tree[root].l >= l && tree[root].r <= r) { mi = min(tree[root].mi , mi); return ; } int mid = (tree[root].l + tree[root].r) >> 1 ; if(l <= mid) query_min(l , r , root*2); if(r > mid) query_min(l , r, root*2+1); } int main() { while(~scanf("%d%d" , &n , &q)) { build(1 , n , 1); stack<int>st; for(int i = 0 ; i < q ; i++) { scanf("%s" , s); if(s[0] == 'D') { int x ; scanf("%d" , &x); st.push(x); update_max(x , x , 1); update_min(x , x , 1); } else if(s[0] == 'R') { int x ; if(!st.empty()) { x = st.top(); update_max(x , 0 , 1); update_min(x , n+1, 1); st.pop(); } else{ continue ; } } else{ int x ; scanf("%d" , &x); ma = -INF , mi = INF ; query_max(1 , x , 1); query_min(x , n , 1); if(mi != ma) printf("%d\n" , mi - ma - 1); else{ printf("0\n"); } } } } return 0; }
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SF(n) scanf("%d" , &n) #define rep(i , n) for(int i = 0 ; i < n ; i ++) #define INF 0x3f3f3f3f #define mod 20191117 #define PI acos(-1) #define gcd __gcd using namespace std; typedef long long ll ; char s[10]; struct node { int l , r , ll , rr , val;//最大左连续,最大右连续,最大连续 }tree[50009*4]; void build(int l , int r , int root) { tree[root].l = l , tree[root].r = r , tree[root].ll = tree[root].rr = tree[root].val = r - l + 1;//初始化为区间长 if(l == r) { return ; } int mid = (l + r) >> 1 ; build(l , mid , root*2); build(mid+1 , r , root*2+1); } void update(int x , int val , int root) { if(tree[root].l == tree[root].r) { tree[root].ll = tree[root].rr = tree[root].val = val ;//将该点左连续、右连续、最长连续更新为val return ; } int mid = (tree[root].l + tree[root].r) >> 1; if(x <= mid) update(x , val , root*2); else update(x , val , root*2+1); //回溯给父节点赋值 if(tree[root*2].r - tree[root*2].l + 1 == tree[root*2].ll)//如果(左儿子的左连续)等于(左儿子的区间长) tree[root].ll = tree[root*2].ll + tree[root*2+1].ll ;//父节点的左连续等于(左儿子的左连续)加(右儿子的左连续) else{ tree[root].ll = tree[root*2].ll ;//否则,(父节点的左连续)等于(左儿子的左连续) } if(tree[root*2+1].r - tree[root*2+1].l + 1 == tree[root*2+1].rr)//(父节点右连续)同理(父节点左连续) tree[root].rr = tree[root*2+1].rr + tree[root*2].rr ; else{ tree[root].rr = tree[root*2+1].rr ; } tree[root].val = max(max(tree[root*2].ll , tree[root*2+1].rr) , tree[root*2].rr + tree[root*2+1].ll);//父节点最长连续等于三者最大(左儿子的左连续、右儿子的右连续、(左儿子的右连续)加上(右儿子的左连续)) } int query(int x , int root) { if(tree[root].l == tree[root].r || tree[root].val == 0 || tree[root].r - tree[root].l + 1 == tree[root].val)//如果为叶子节点、最长区间为0,区间长等于最长区间。返回最长区间值 return tree[root].val ; int mid = (tree[root].l + tree[root].r) >> 1 ; if(x <= mid)//目标在左儿子 { if(x >= tree[root*2].r - tree[root*2].rr + 1)//目标在左儿子的右连续区间 return tree[root*2].rr + tree[root*2+1].ll ;//返回左儿子的右连续区间和右儿子的左连续区间 else{ return query(x , root*2);//不在右连续区间,递归左儿子 } } else{//目标在右儿子 if(x <= tree[root*2+1].l + tree[root*2+1].ll - 1)//在右儿子的左区间 return tree[root*2].rr + tree[root*2+1].ll ;//返回右儿子的左连续和左儿子的右连续 else{ return query(x , root*2+1);//递归右儿子 } } } int main() { int n , m ; while(~scanf("%d%d" , &n , &m)) { build(1 , n , 1); stack<int>st; for(int i = 0 ; i < m ; i++) { scanf("%s" , s); if(s[0] == 'D') { int x ; scanf("%d" , &x); update(x , 0 , 1); st.push(x); } else if(s[0] == 'R') { int x = st.top(); update(x , 1 , 1); st.pop(); } else{ int x ; scanf("%d" , &x); printf("%d\n" , query(x , 1)); } } } return 0; }