线段树 - 区间合并
1.
The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).
The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.
Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.
Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Line i+1
contains request expressed as one of two possible formats: (a) Two
space separated integers representing a check-in request: 1 and Di (b) Three space-separated integers representing a check-out: 2, Xi, and Di
* Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.
10 6 1 3 1 3 1 3 1 3 2 5 5 1 6Sample Output
1 4 7 0 5
题意 : 有一串连续的房子,里面全是空着的,有两种操作,第一种操作,是询问所有的房子中,有没有空闲的够且连续长度够输入的要求,如果有,输出最左边的编号,如果没有,输出 0 。
第二种操作,清空一串连续的房间。
思路 :
典型的线段树中的区间合并, 这题 有个地方要注意下,就是 懒标记下传册时候好坑!! 区间更新时,题目中是有两种操作的,所有会有两种形态的区间下传操作,懒标记初始形态是 -1,当有客人入住时,将懒标记记为 1, 当客人离开时,将懒标记记为 0, 在懒标记下传后,要将懒标记重新归为 -1.
代码示例 :
const int eps = 5e4+5; const double pi = acos(-1.0); const int inf = 1<<29; #define Max(a,b) a>b?a:b #define Min(a,b) a>b?b:a #define ll long long #define lson k<<1 #define rson k<<1|1 struct node { int l, r; int lm, rm, sm; int f; }tree[eps<<2]; void build(int l, int r, int k){ tree[k].l = l; tree[k].r = r; tree[k].lm = tree[k].rm = tree[k].sm = r-l+1; tree[k].f = -1; if (l == r) return; int m = (l + r) >> 1; build(l, m, lson); build(m+1, r, rson); } void pushdown(int k){ if (tree[k].f == -1) return; if (tree[k].f == 1) { tree[k].f = -1; tree[lson].f = tree[rson].f =1; tree[lson].lm = tree[lson].rm = tree[lson].sm = 0; tree[rson].lm = tree[rson].rm = tree[rson].sm = 0; } else { tree[k].f = -1; tree[lson].f = tree[rson].f = 0; tree[lson].lm = tree[lson].rm = tree[lson].sm = (tree[lson].r - tree[lson].l + 1); tree[rson].lm = tree[rson].rm = tree[rson].sm = (tree[rson].r - tree[rson].l + 1); } } int query(int len, int k){ if (tree[k].lm >= len){ return tree[k].l; } pushdown(k); int ans = 99999; if (tree[lson].sm >= len) ans = min(ans, query(len, lson)); else if (tree[lson].rm + tree[rson].lm >= len) ans = min(ans, tree[lson].r - tree[lson].rm + 1); else ans = min(ans, query(len, rson)); return ans; } void pushup(int k){ tree[k].lm = tree[lson].lm; tree[k].rm = tree[rson].rm; tree[k].sm = max(tree[lson].sm, tree[rson].sm); if ((tree[lson].r - tree[lson].l + 1 ) == tree[lson].lm){ tree[k].lm += tree[rson].lm; } if ((tree[rson].r - tree[rson].l + 1) == tree[rson].rm){ tree[k].rm += tree[lson].rm; } tree[k].sm = max(tree[k].sm, tree[lson].rm + tree[rson].lm); } void update(int l, int r, int pt, int k){ if (l <= tree[k].l && tree[k].r <= r){ if (pt == 1) { tree[k].f = 1; tree[k].lm = tree[k].rm = tree[k].sm = 0; } else { tree[k].f = 0; tree[k].lm = tree[k].rm = tree[k].sm = (tree[k].r - tree[k].l + 1); } return ; } pushdown(k); int m = (tree[k].l + tree[k].r) >> 1; if (tree[k].f) pushdown(k); if (l <= m) update(l, r, pt, lson); if (r > m) update(l, r, pt, rson); pushup(k); } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int n, m; int x, a, b; //cin >>n >> m; while(~scanf("%d%d", &n, &m)){ build(1, n, 1); for(int i = 1; i <= m; i++){ scanf("%d", &x); if (x == 1) { scanf("%d", &a); if (tree[1].sm < a) printf("0\n"); else { int ans = query(a, 1); update(ans, ans+a-1, 1, 1); printf("%d\n", ans); } } else { scanf("%d%d", &a, &b); update(a, a+b-1, 0, 1); } } } return 0; }
2 .
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].
InputT in the first line, indicating the case number.
Each case starts with two integers n , m(0<n,m<=10 5).
The next line has n integers(0<=val<=10 5).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=10 5)
OR
Q A B(0<=A<=B< n).
OutputFor each Q, output the answer.Sample Input
1 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9Sample Output
1 1 4 2 3 1 2 5
题目分析 :题目分析 : 给你 n 个整数,两种操作,一是 替换操作,而是查询区间内有多少个连续的递增数 。
思路 : 线段树 中的区间合并,节点中定义三个量,lm, rm, sm , 分别表示的含义是包含包含区间左端点,右端点在内的最大递增数列, sm 表示区间的最长递增数列。
代码示例 :
const int eps = 1e5+5; const double pi = acos(-1.0); const int inf = 1<<29; #define Max(a,b) a>b?a:b #define Min(a,b) a>b?b:a #define ll long long #define lson k<<1 #define rson k<<1|1 int pre[eps]; struct node { int l, r; int lm, rm, sm; }tree[eps<<2]; void pushup(int k){ tree[k].lm = tree[lson].lm; tree[k].rm = tree[rson].rm; tree[k].sm = max(tree[lson].sm, tree[rson].sm); int m = (tree[k].l + tree[k].r) >> 1; if (pre[m] < pre[m+1]){ if (tree[lson].lm == (tree[lson].r - tree[lson].l + 1)){ tree[k].lm += tree[rson].lm; } if (tree[rson].rm == (tree[rson].r - tree[rson].l + 1)){ tree[k].rm += tree[lson].rm; } tree[k].sm = max(tree[k].sm, tree[lson].rm + tree[rson].lm); } } void build(int l, int r, int k){ tree[k].l = l, tree[k].r = r; if (l == r){ tree[k].lm = tree[k].rm = tree[k].sm = 1; return; } int m = (l + r) >> 1; build(l, m, lson); build(m+1, r, rson); pushup(k); } int query(int l, int r, int k){ if (l <= tree[k].l && tree[k].r <= r){ return tree[k].sm; } int m = (tree[k].l + tree[k].r) >> 1; int ans = 1; if (l <= m) ans = max(ans, query(l, r, lson)); if (r > m) ans = max(ans, query(l, r, rson)); if (pre[m] < pre[m+1]){ int lf = min(tree[lson].rm, m-l+1); int rf = min(tree[rson].lm, r-m); ans = max(ans, lf+rf); } return ans; } void update(int a, int b, int k){ if (tree[k].l == tree[k].r){ pre[a] = b; return; } int m = (tree[k].l + tree[k].r) >> 1; if (a <= m) update(a, b, lson); else update(a, b, rson); pushup(k); } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int t; int n, m; int a, b; char s[10]; cin >> t; while(t--){ cin >> n >> m; for(int i = 1; i <= n; i++){ scanf("%d", &pre[i]); } build(1, n, 1); for(int i = 1; i <= m; i++){ scanf("%s%d%d", s, &a, &b); if (s[0] == 'U') update(a+1, b, 1); else printf("%d\n", query(a+1, b+1, 1)); } } return 0; }
3 .
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!
InputThe 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.
OutputOutput 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 4Sample Output
1 0 2 4
题目分析 :题意 : 有一排村庄 , D 表示毁掉此村庄 , R 表示重建最后一个被毁掉的村庄 , Q 表示查询所输入的村庄与多少村庄相连, 要包括他本身 。
思路 :此类题目属于线段树里的区间合并 , 问最多有多少相连的区间 , 其实他与普通的单点查询差不多 ,但是会在结构体中多存三个量 , lm, rm, mm 分别表示当前区间从最左边数的最大连续长度 , 从右边数的最大连续长度 , 当前区间的最大连续长度 。<br>其中 lm, rm 的作用是判断 是否要查询的点的另一侧范围在继续查找 , mm 的作用则是当当前区间到底 , 或是所要查找的点就在这个区间 为 空或为满的情况 。
代码示例 :
const int eps = 5e4+5; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; #define Max(a,b) a>b?a:b #define Min(a,b) a>b?b:a #define ll long long #define lson l, m, k<<1 #define rson m+1, r, k<<1|1 stack<int>s; struct node { int l, r; int lm, rm, mm; }tree[eps<<2]; int ff, ans; void build(int l, int r, int k){ tree[k].l = l; tree[k].r = r; tree[k].lm = tree[k].rm = tree[k].mm = (r - l + 1); if (l == r){ return; } int m = (tree[k].l + tree[k].r) >> 1; build(lson); build(rson); } void update(int l, int r, int k, int pt){ if (l == r){ if (!pt) { tree[k].lm = tree[k].rm = tree[k].mm = 0; } else tree[k].lm = tree[k].rm = tree[k].mm = 1; return; } int m = (tree[k].l + tree[k].r) >> 1; if (ff <= m) update(lson, pt); else update(rson, pt); tree[k].lm = tree[k<<1].lm; tree[k].rm = tree[k<<1|1].rm; tree[k].mm = tree[k<<1].rm + tree[k<<1|1].lm; if (tree[k<<1].lm == (tree[k<<1].r - tree[k<<1].l + 1)) tree[k].lm = tree[k<<1].lm + tree[k<<1|1].lm; if (tree[k<<1|1].rm == (tree[k<<1|1].r - tree[k<<1|1].l + 1)) tree[k].rm = tree[k<<1|1].rm + tree[k<<1].rm; //tree[k].mm = max(max(tree[k<<1].mm, tree[k<<1|1].mm), tree[k<<1].rm + tree[k<<1|1].lm); } void query(int l, int r, int k, int key){ if (l == r || tree[k].mm == 0 || tree[k].mm == (r - l + 1)){ ans += tree[k].mm; return; } int m = (tree[k].l + tree[k].r) >> 1; if (key <= m){ int pt = tree[k<<1].r - tree[k<<1].rm + 1; if (key >= pt){ query(lson, key); query(rson, m+1); } else query(lson, key); } else { int pt = tree[k<<1|1].l + tree[k<<1|1].lm - 1; if (key <= pt){ query(rson, key); query(lson, m); } else query(rson, key); } } int main() { int n, m; char ch[5]; while (~scanf("%d%d", &n, &m)){ while (!s.empty()){ s.pop(); } //cin >> n >> m; build(1, n, 1); while (m--){ scanf("%s", ch); if (ch[0] == 'D') { scanf("%d", &ff); s.push(ff); update(1, n, 1, 0); } else if (ch[0] == 'Q'){ scanf("%d", &ff); ans = 0; query(1, n, 1, ff); printf("%d\n", ans); } else { ff = s.top(); s.pop(); update(1, n, 1, 1); } } } return 0; }