hdu-1540(线段树+区间合并)
Posted wyh344866
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu-1540(线段树+区间合并)相关的知识,希望对你有一定的参考价值。
Tunnel Warfare
思路:
没被摧毁的村庄为1,否则为0,用len记录
线段树维护区间的两个信息:
前缀最长1的序列pre
后缀最长1的序列suf
父节点与左右子节点的关系:
//lc为左节点,rc为右节点
1.若左右结点都不满1,则tr[p].pre = tr[lc].pre,tr[p].suf = tr[rc].suf
2.若左节点满1,tr[p].pre = tr[lc].pre + tr[rc].pre;
3.若右节点满1,tr[p].suf = tr[lc].suf + tr[rc].suf;
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<algorithm>
#include<fstream>
#include<iostream>
#include<cstdio>
#include<deque>
#include<string>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<unordered_map>
using namespace std;
#define INF 2e9
#define MAXN 310000
#define N 1000010
#define M 10007
#define endl \'\\n\'
#define exp 1e-8
#define lc p << 1
#define rc p << 1|1
#define lowbit(x) ((x)&-(x))
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
inline ULL read()
ULL x = 0, f = 1;
char ch = getchar();
while (ch < \'0\' || ch>\'9\')
if (ch == \'-\')
f = -1;
ch = getchar();
while (ch >= \'0\' && ch <= \'9\')
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
return x * f;
void print(ULL x)
if (x > 9)print(x / 10);
putchar(x % 10 ^ 48);
int n, m,idx,his[N];
struct tree
int l, r, len, pre, suf;
tr[N*4];
void pushup(int p)
int len = tr[p].r - tr[p].l + 1;
tr[p].pre = tr[lc].pre;
tr[p].suf = tr[rc].suf;
if (len - (len >> 1) == tr[lc].pre) tr[p].pre = tr[lc].pre + tr[rc].pre;
if (len >> 1 == tr[rc].suf) tr[p].suf = tr[lc].suf + tr[rc].suf;
void build(int p, int l, int r)
tr[p].l = l, tr[p].r = r;
if (l == r)
tr[p].len = tr[p].pre = tr[p].suf = 1;
return;
int m = l + r >> 1;
build(lc, l, m);
build(rc, m + 1, r);
pushup(p);
void update(int p, int x,int c )
if (tr[p].l == tr[p].r)
tr[p].suf = tr[p].pre = tr[p].len = c;
return;
int m = tr[p].l + tr[p].r >> 1;
if (x <= m)update(lc, x, c);
else update(rc, x, c);
pushup(p);
int query(int p, int x)
if (tr[p].l == tr[p].r)
return tr[p].len;
int m = tr[p].l + tr[p].r >> 1;
if (x <= m)
if (x > m - tr[lc].suf)return tr[lc].suf + tr[rc].pre;
else return query(lc, x);
else
if (x <= m + tr[rc].pre)return tr[lc].suf + tr[rc].pre;
else return query(rc, x);
int main()
while (scanf("%d%d", &n, &m) != EOF)
build(1, 1, n);
idx = 0;
while (m--)
char a;
int x;
cin >> a;
if (a == \'D\')
scanf("%d", &x);
his[++idx] = x;
update(1, x, 0);
else if (a == \'Q\')
scanf("%d", &x);
printf("%d\\n", query(1, x));
else
x= his[idx--];
update(1, x, 1);
return 0;
HDU 3308 LCIS (线段树区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308
题目很好懂,就是单点更新,然后求区间的最长上升子序列。
线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1e5 + 5; 6 struct SegTree { 7 int l , r , lsum , sum , rsum; 8 }T[MAXN << 2]; 9 int a[MAXN]; 10 11 void pushup(int p) { 12 int ls = p << 1 , rs = (p << 1)|1 , mid = (T[p].r + T[p].l) >> 1; 13 T[p].lsum = T[ls].lsum , T[p].rsum = T[rs].rsum; 14 if(T[p].lsum == T[ls].r - T[ls].l + 1) { 15 T[p].lsum += (a[mid + 1] > a[mid] ? T[rs].lsum : 0); 16 } 17 if(T[p].rsum == T[rs].r - T[rs].l + 1) { 18 T[p].rsum += (a[mid + 1] > a[mid] ? T[ls].rsum : 0); 19 } 20 T[p].sum = max(T[ls].sum , T[rs].sum); 21 int temp = (a[mid + 1] > a[mid] ? T[ls].rsum + T[rs].lsum : 1); 22 T[p].sum = max(temp , T[p].sum); 23 } 24 25 void build(int p , int l , int r) { 26 int mid = (l + r) >> 1; 27 T[p].l = l , T[p].r = r; 28 if(l == r) { 29 T[p].lsum = T[p].rsum = T[p].sum = 1; 30 return ; 31 } 32 build(p << 1 , l , mid); 33 build((p << 1)|1 , mid + 1 , r); 34 pushup(p); 35 } 36 37 void updata(int p , int pos , int num) { 38 int mid = (T[p].l + T[p].r) >> 1; 39 if(T[p].l == T[p].r && T[p].l == pos) { 40 a[pos] = num; 41 return ; 42 } 43 if(pos <= mid) { 44 updata(p << 1 , pos , num); 45 } 46 else { 47 updata((p << 1)|1 , pos , num); 48 } 49 pushup(p); 50 } 51 52 int query(int p , int l , int r) { 53 int mid = (T[p].l + T[p].r) >> 1; 54 if(l == T[p].l && T[p].r == r) { 55 return T[p].sum; 56 } 57 if(r <= mid) { 58 return query(p << 1 , l , r); 59 } 60 else if(l > mid) { 61 return query((p << 1)|1 , l , r); 62 } 63 else { 64 return max((a[mid + 1] > a[mid] ? min(mid - l + 1 , T[p << 1].rsum) + min(T[(p << 1)|1].lsum , r - mid) : 1) , 65 max(query(p << 1 , l , mid) , query((p << 1)|1 , mid + 1 , r) ) ); 66 } 67 } 68 69 int main() 70 { 71 int t , n , m; 72 scanf("%d" , &t); 73 while(t--) { 74 scanf("%d %d" , &n , &m); 75 for(int i = 1 ; i <= n ; ++i) { 76 scanf("%d" , a + i); 77 } 78 build(1 , 1 , n); 79 char q[5]; 80 int l , r; 81 while(m--) { 82 scanf("%s %d %d" , q , &l , &r); 83 if(q[0] == ‘Q‘) { 84 printf("%d\n" , query(1 , l + 1 , r + 1)); 85 } 86 else { 87 updata(1 , l + 1 , r); 88 } 89 } 90 } 91 return 0; 92 }
以上是关于hdu-1540(线段树+区间合并)的主要内容,如果未能解决你的问题,请参考以下文章
HDU 1540 Tunnel Warfare(区间合并)线段树