HDU 1540 Tunnel Warfare(线段树 区间合并)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 1540 Tunnel Warfare(线段树 区间合并)相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540
题意:n个村子,相邻两个村子初始都是联通的,询问经过一些操作后村子x最多和几个村子联通(包括村子x)。
操作的话有破坏(破坏相当于村子消失)和修复(修复是以栈的形式顺序)
题解:
1 //HDU 1540 Tunnel Warfare 2 //线段树 区间合并 3 #include <stack> 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 9 typedef long long LL; 10 const int N=50000+10; 11 12 struct Tree 13 { 14 LL l,r; 15 LL prelen,nextlen,maxlen; 16 //左端最大连续区间,右端最大连续区间,区间内最大连续区间 17 }; 18 Tree tree[4*N]; 19 20 void pushup(LL x) //向上更新 21 { 22 LL tmp=x<<1; 23 tree[x].prelen=tree[tmp].prelen; 24 tree[x].nextlen=tree[tmp+1].nextlen; 25 tree[x].maxlen=max(tree[tmp].maxlen,tree[tmp+1].maxlen); 26 tree[x].maxlen=max(tree[x].maxlen,tree[tmp].nextlen+tree[tmp+1].prelen); 27 //最大区间为左右儿子的最大区间和(左儿子的右端最大区间+右儿子的左端最大区间)中的最大值 28 //左 中 右 选择问题 29 30 if(tree[tmp].prelen==tree[tmp].r-tree[tmp].l+1) //左儿子左端区间满值,父亲加上右儿子的左端区间 31 tree[x].prelen+=tree[tmp+1].prelen; 32 33 if(tree[tmp+1].nextlen==tree[tmp+1].r-tree[tmp+1].l+1) //右儿子右区间满值,父亲加上左儿子的右端区间 34 tree[x].nextlen+=tree[tmp].nextlen; 35 } 36 37 void build(LL l,LL r,LL x) 38 { 39 tree[x].l=l; 40 tree[x].r=r; 41 tree[x].maxlen=tree[x].prelen=tree[x].nextlen=r-l+1; 42 if(l==r) return ; 43 LL tmp=x<<1; 44 LL mid=(l+r)>>1; 45 build(l,mid,tmp); 46 build(mid+1,r,tmp+1); 47 } 48 49 void update(LL k,LL c,LL x) 50 { 51 if(k<tree[x].l||k>tree[x].r) return ; 52 if(tree[x].l==k&&tree[x].r==k) 53 { 54 tree[x].maxlen=tree[x].prelen=tree[x].nextlen=c; 55 return ; 56 } 57 LL tmp=x<<1; 58 LL mid=(tree[x].l+tree[x].r)>>1; 59 if(k<=mid) update(k,c,tmp); 60 else update(k,c,tmp+1); 61 pushup(x); 62 } 63 64 LL query(LL k,LL x) 65 { 66 if(tree[x].l==tree[x].r||tree[x].maxlen==tree[x].r-tree[x].l+1||tree[x].maxlen==0){ 67 return tree[x].maxlen; 68 } //询问到满值或者0或者叶子节点就必要继续往下找 69 LL tmp=x<<1; 70 LL mid=(tree[x].l+tree[x].r)>>1; 71 if(k<=mid){ //寻找的点在左儿子的右端区域,很可能可以连接右儿子,所以还要在右儿子那边找下 72 if(k>=tree[tmp].r-tree[tmp].nextlen+1) return query(k,tmp)+query(mid+1,tmp+1); 73 else return query(k,tmp); //否则直接在左儿子的左端区域找 74 } 75 else{ //同理(滑稽.jpg) 76 if(k<=tree[tmp+1].l+tree[tmp+1].prelen-1) return query(mid,tmp)+query(k,tmp+1); 77 else return query(k,tmp+1); 78 } 79 } 80 81 int main(){ 82 LL n,m,A; 83 char op[2]; 84 while(scanf("%lld%lld",&n,&m)!=EOF){ 85 stack <LL> S; 86 build(1,n,1); 87 for(int i=1;i<=m;i++){ 88 scanf("%s",op); 89 if(op[0]==‘D‘){ 90 scanf("%lld",&A); 91 S.push(A); 92 update(A,0,1); 93 } 94 else if(op[0]==‘Q‘){ 95 scanf("%lld",&A); 96 printf("%lld\n",query(A,1)); 97 } 98 else if(op[0]==‘R‘){ 99 if(!S.empty()){ 100 A=S.top();S.pop(); 101 update(A,1,1); 102 } 103 } 104 } 105 } 106 return 0; 107 }
以上是关于HDU 1540 Tunnel Warfare(线段树 区间合并)的主要内容,如果未能解决你的问题,请参考以下文章
HDU1540 Tunnel Warfare —— 线段树 区间合并
hdu1540 Tunnel Warfare 线段树/树状数组