【线段树区间合并】HDU1540-Tunnel Warfare

一、题目

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!

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.

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

顺便附上原题链接→_→Problem-1540

二、题目分析

和普通的线段树没什么太大差别,只是每个区间加了两个变量——lsum和rsum,分别表示这个区间左起向右连续“1”串的长度和右起向左连续“1”串的长度。在维护树回溯时,一个区间的lsum等于其左区间的lsum,rsum等于其右区间的rsum。特别的,当一个区间左区间的lsum等于其左区间长度,即该区间左区间是一个连续的“1”串时,该区间lsum需额外加上其右区间的lsum;对于其rsum同理。

三、代码实现

这题有个天坑,题目完全没提到,但这题有多组数据_(:з」∠)_

  1 #include<cstdio>
  2 #include<cstring>
  3 const int MAXN=5e4+10;
  4 int n,m;
  5 struct node
  6 {
  7     int l,r;
  8     int lsum,rsum;
  9 }tr[MAXN<<2];
 10 int stack[MAXN],top;
 11 void build(int x,int y,int i)
 12 {
 13     tr[i].l=x,tr[i].r=y;
 14     if(x==y)
 15     {
 16         tr[i].lsum=1;
 17         tr[i].rsum=1;
 18         return;
 19     }
 20     int mid=(tr[i].l+tr[i].r)>>1;
 21     build(x,mid,i<<1);
 22     build(mid+1,y,i<<1|1);
 23     tr[i].lsum=y-x+1,tr[i].rsum=y-x+1;
 24     return;
 25 }
 26 void update(int x,int i,int val)
 27 {
 28     if(tr[i].l==x&&tr[i].r==x)
 29     {
 30         tr[i].lsum=val;
 31         tr[i].rsum=val;
 32         return;
 33     }
 34     int mid=(tr[i].l+tr[i].r)>>1;
 35     if(x<=mid)
 36     {
 37         update(x,i<<1,val);
 38
 39     }
 40     else
 41     {
 42         update(x,i<<1|1,val);
 43     }
 44     tr[i].lsum=tr[i<<1].lsum;
 45     tr[i].rsum=tr[i<<1|1].rsum;
 46     if(tr[i<<1].lsum==tr[i<<1].r-tr[i<<1].l+1)tr[i].lsum+=tr[i<<1|1].lsum;
 47     if(tr[i<<1|1].rsum==tr[i<<1|1].r-tr[i<<1|1].l+1)tr[i].rsum+=tr[i<<1].rsum;
 48 }
 49 int query_left(int x,int i)
 50 {
 51     if(tr[i].r==x)
 52     {
 53         if(tr[i].rsum==tr[i].r-tr[i].l+1&&tr[i].l!=1)
 54         {
 55             return tr[i].rsum+query_left(tr[i].l-1,1);
 56         }
 57         return tr[i].rsum;
 58     }
 59     int mid=(tr[i].l+tr[i].r)>>1;
 60     if(x<=mid)
 61     {
 62         return query_left(x,i<<1);
 63     }
 64     else
 65     {
 66         return query_left(x,i<<1|1);
 67     }
 68 }
 69 int query_right(int x,int i)
 70 {
 71
 72     if(tr[i].l==x)
 73     {
 74         if(tr[i].lsum==tr[i].r-tr[i].l+1&&tr[i].r!=n)
 75         {
 76             return tr[i].lsum+query_right(tr[i].r+1,1);
 77         }
 78         return tr[i].lsum;
 79     }
 80     int mid=(tr[i].l+tr[i].r)>>1;
 81     if(x<=mid)
 82     {
 83         return query_right(x,i<<1);
 84     }
 85     else
 86     {
 87         return query_right(x,i<<1|1);
 88     }
 89 }
 90 int main()
 91 {
 92     while(scanf("%d%d",&n,&m)!=EOF)
 93     {
 94         memset(tr,0,sizeof(tr));
 95         memset(stack,0,sizeof(stack));
 96         top=0;
 97         build(1,n,1);
 98         for(int i=1;i<=m;++i)
 99         {
100             char c;
101             int x;
102             scanf("\n%c",&c);
103             if(c==‘D‘)
104             {
105                 scanf("%d",&x);
106                 stack[++top]=x;
107                 update(x,1,0);
108             }
109             else if(c==‘R‘)
110             {
111                 update(stack[top--],1,1);
112             }
113             else
114             {
115                 scanf("%d",&x);
116                 int ans=query_left(x,1)+query_right(x,1)-1;
117                 if(ans<=0)printf("0\n");
118                 else printf("%d\n",ans);
119             }
120         }
121     }
122     return 0;
123 }

HDU1540-Tunnel Warfare

弱弱地说一句,本蒟蒻码字也不容易,转载请注明出处http://www.cnblogs.com/Maki-Nishikino/p/6230606.html

时间: 2024-08-26 12:23:50

【线段树区间合并】HDU1540-Tunnel Warfare的相关文章

POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】

Hotel Time Limit: 3000MS Memory Limit: 65536K 链接:POJ 3667   Description The cows are journeying north to ThunderBay in Canada to gain cultural enrichment and enjoy a vacation on the sunnyshores of Lake Superior. Bessie, ever the competent travel agen

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

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 = 1

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

hdu3911 线段树 区间合并

1 //Accepted 3911 750MS 9872K 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a documen

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>

【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少.1 ≤ n ≤ 105,1 ≤ m ≤ 105,1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 20 Sample Input 9 9 -8 9 -1 -1 -1 9 -8 9 3 1 1 9 1 1 1 9 2 1 4 6 3 Sample Output 17 25

HDU 3308 LCIS(最长连续上升子序列)(线段树区间合并)

题意:给你n个整数,有两种操作,U A B把第A个数变成B,Q A B查询区间[A,B]的最长连续上升序列. 思路:还是查询和更新操作,而且也是询问区间中满足条件的连续最长区间 ,所以是线段树区间合并类型的题,通法是开三棵线段树,一个记录此区间内的LCIS的最长长度,一个记录从左边第一个数开始的LCIS长度,另一个记录从右边最后一个数结尾的LCIS长度.然后试图找到父亲与儿子关系维护的递推关系式就好 本题中的递推关系是: 1. 左儿子最右边的值 < 右儿子最左边的值 lmx = (左儿子的lmx