hdu1540 Tunnel Warfare 线段树/树状数组

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!

题意是有一个线段上排列着很多村庄,现在有三个操作,一个是炸毁一个村庄,是它与两边都不连通,一个是修复一个村庄,还有一个是查询某个村庄,它向左右两边一共可以连通多少村庄。

虽然同样是线段树,网上很多题解都写的用线段树节点记录左边连续的长度和右边连续的长度,我刚学习线段树的时候因为不熟悉线段树的思路,也就照着理解了写的,但是我一直觉得这种做法很麻烦,容易写错,大概网上都是互抄博客吧。

我的思路是查询一个村庄能连通多少村庄,其实就是查询它左右两边最近的一个被毁掉的村庄分别是哪个,比如 5 号村庄,离它最近的被毁掉的村庄分别是 3 号和 8 号,那么它连通的就是 4~7 号村庄,就是(8-3-1)个村庄了。那么我就是让被毁的村庄显示在线段树里,我只要能够查询到它,就可以解决问题。比如离 5 号村庄最近的两个村庄应该是什么样的:1~4 号中被摧毁且编号最大的,与 6~n 号中被摧毁且编号最小的。那么我其实只要求两个区间内的最大与最小值就行了,这就可以写最基础的单点修改、区间求最值的线段树。

具体方法是:

首先最大值树中初始所有值都是-1,每摧毁一个点,就在它的位置上更新成它的编号,如 摧毁 3 号点,就将 3 这个位置更新成 3,这样被摧毁的点在线段树上的值是它的编号,可以用于直接查询最值,而没有被摧毁的则是 -1,不会影响。修复村庄则是更新回-1。

最小值树则相反,初始值是一个极大值(我用的是0x3f3f3f3f),摧毁点同样更新成编号,修复同样更新回极大值。

然后查询就直接查左边区间的最大值和右边区间的最小值就可以了。

细节是:

由于有某一边还没有村庄被摧毁,所有都是-1或极大值,这样需要特判。为了巧妙解决这个问题,我就在一开始初始化时,顺便摧毁 0 号点和 n+1号点,这两个不存在的点,这样查询的时候就无需特判也能直接这么做了。

当然,树状数组也可以完成上述的操作。

 1 #include<stdio.h>
 2 #include<string.h>
 3 const int maxm=5e4+5;
 4 const int INF=0x3f3f3f3f;
 5
 6 int ma[maxm<<2],mi[maxm<<2];
 7 int sta[maxm],cnt;
 8 int maxx,minn;
 9 char s[10];
10
11 int max(int a,int b){return a>b?a:b;}
12 int min(int a,int b){return a<b?a:b;}
13
14 void update(int o,int l,int r,int ind,int c){
15     if(l==r){
16         if(c==1){
17             ma[o]=-1;
18             mi[o]=INF;
19         }
20         else ma[o]=mi[o]=l;
21         return;
22     }
23     int m=l+((r-l)>>1);
24     if(ind<=m)update(o<<1,l,m,ind,c);
25     else update(o<<1|1,m+1,r,ind,c);
26     ma[o]=max(ma[o<<1],ma[o<<1|1]);
27     mi[o]=min(mi[o<<1],mi[o<<1|1]);
28 }
29
30 void query1(int o,int l,int r,int ql,int qr){
31     if(ql<=l&&qr>=r){
32         maxx=max(maxx,ma[o]);
33         return;
34     }
35     int m=l+((r-l)>>1);
36     if(ql<=m)query1(o<<1,l,m,ql,qr);
37     if(qr>=m+1)query1(o<<1|1,m+1,r,ql,qr);
38 }
39
40 void query2(int o,int l,int r,int ql,int qr){
41     if(ql<=l&&qr>=r){
42         minn=min(minn,mi[o]);
43         return;
44     }
45     int m=l+((r-l)>>1);
46     if(ql<=m)query2(o<<1,l,m,ql,qr);
47     if(qr>=m+1)query2(o<<1|1,m+1,r,ql,qr);
48 }
49
50 int main(){
51     int n,m;
52     while(scanf("%d%d",&n,&m)!=EOF){
53         cnt=0;
54         memset(ma,-1,sizeof(ma));
55         memset(mi,0x3f,sizeof(mi));
56         update(1,0,n+1,0,0);
57         update(1,0,n+1,n+1,0);
58         for(int i=1;i<=m;++i){
59             scanf("%s",s);
60             if(s[0]==‘D‘){
61                 int ind;
62                 scanf("%d",&ind);
63                 update(1,0,n+1,ind,0);
64                 sta[++cnt]=ind;
65             }
66             else if(s[0]==‘Q‘){
67                 int ind;
68                 scanf("%d",&ind);
69                 maxx=-1;
70                 minn=INF;
71                 query1(1,0,n+1,0,ind);
72                 query2(1,0,n+1,ind,n+1);
73                 if(minn==maxx)printf("0\n");
74                 else printf("%d\n",minn-maxx-1);
75             }
76             else if(s[0]==‘R‘){
77                 update(1,0,n+1,sta[cnt--],1);
78             }
79         }
80     }
81     return 0;
82 }

时间: 2024-10-27 06:47:34

hdu1540 Tunnel Warfare 线段树/树状数组的相关文章

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

HDU1540 Tunnel Warfare

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 vill

kuangbin专题七 HDU1540 Tunnel Warfare (前缀后缀线段树)

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 con

hdu--1540 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

hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并

Tunnel Warfare Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1540 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Gene

HDU 1540 Tunnel Warfare 线段树区间合并

Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区间,左儿子的最大连续右区间+右儿子的最大连续左区间)决定 所以线段树的节点应该维护当前节点的最大连续左区间,最大连续右区间,和最大连续区间. 注意更新的时候,如果左儿子全满,父亲节点的左连续区间还要加上右儿子的左区间.反之同理. 查询的时候,可以剪枝,如果是叶子,或为空,或满,则不用往下查询. 查询

hdu 1540 Tunnel Warfare(线段树)

题目链接:hdu 1540 Tunnel Warfare 题目大意:有连续的N个城镇,三种操作: D x:第x城镇被破坏 Q x:插叙第x城镇所在联通块有多少个城镇没有被破坏 R:修复最后一个被破坏的城镇 解题思路:线段树区间合并,每个城镇看成一个叶子节点,用一个vector记录破坏顺序.对于查询来说,每次只要判断是否在mid?R[lson(u)],mid+L[rson(u)]之间即可,否则即递归查询左右子树. #include <cstdio> #include <cstring>

HDU 1540 Tunnel Warfare(线段树单点更新+区间合并)

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 vill

线段树&amp;数状数组

线段树 单点修改,区间查询 #include<bits/stdc++.h> using namespace std; int n,q; long long num[1000010]; struct tree { int l,r; long long sum,max; }t[4000010]; void BuildTree(int,int,int); void Update(int,int,int,int,long long); long long Query(int,int,int,int,i