码迷,mamicode.com
首页 > 其他好文 > 详细

HDU1540线段树维护连续子区间

时间:2020-11-07 16:41:07      阅读:22      评论:0      收藏:0      [点我收藏+]

标签:abs   最大   turn   sdn   empty   signed   tran   数据   区间   

------------恢复内容开始------------

感谢大佬的博客,受益匪浅

https://blog.csdn.net/weixin_42469716/article/details/102938021?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160431756819195264713806%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160431756819195264713806&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-102938021.pc_first_rank_v2_rank_v28p&utm_term=hdu1540&spm=1018.2118.3001.4449

题目大意

1-n个地道,m个次操作,D代表摧毁第i个地道,Q代表查询包含第i个地道的最大连续地道数目,并输出。R代表修复最近摧毁的那个地道

解题思路

R表示修复最近摧毁的那个通道,所以自然而然的想利用栈来解决,Q代表查询包含第i个地道的最大连续地道数目,这个就表示要求求出包含在本节点在内的最大连续区间的和。这里要用到求子区间和的方法,

求最大连续区间的和的方法:维护区间中从左节点开始的最大连续区间和区间中从右节点开始的最大连续区间和,以及在这个区间中最大连续区间和

void up(int p){
   //计算左端开始的连续和      
    t[p].ls=t[p<<1].ls;
    if(t[p<<1].ls==t[p<<1].r-t[p<<1].l+1)t[p].ls+=t[p<<1|1].ls;
    //计算右端开始的连续和
    t[p].rs=t[p<<1|1].rs;
    if(t[p<<1|1].rs==t[p<<1|1].r-t[p<<1|1].l+1)t[p].rs+=t[p<<1].rs;
//计算最大连续和   t[p].m=max(t[p<<1].rs+t[p<<1|1].ls,max(t[p<<1].m,t[p<<1|1].m));
}

 剩下的就是单点修改,单点查询的线段树板子

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <iomanip>
 5 #include <string.h>
 6 #include <cstring>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <map>
10 #include <stack>
11 #include <utility>
12 using namespace std;
13 typedef long long ll ;
14 typedef unsigned long long ull ;
15 const int N=1e5+90;
16 const int inf=1e9+90;
17 #define eps 1e-10
18 #define forn(i,n) for(int i=0;i<n;i++)
19 #define form(i,n) for(int i=1;i<=n;i++)
20 ll a[N];
21 int n,m;
22 char c[4];
23 struct Node{
24     int l,r;
25     ll ls,rs,m;
26 }t[N<<2];
27 void up(int p){
28     t[p].ls=t[p<<1].ls;
29     if(t[p<<1].ls==t[p<<1].r-t[p<<1].l+1)t[p].ls+=t[p<<1|1].ls;
30     t[p].rs=t[p<<1|1].rs;
31     if(t[p<<1|1].rs==t[p<<1|1].r-t[p<<1|1].l+1)t[p].rs+=t[p<<1].rs;
32     t[p].m=max(t[p<<1].rs+t[p<<1|1].ls,max(t[p<<1].m,t[p<<1|1].m));
33 }
34 void build(int l,int r,int p){
35     if(l==r){
36         t[p]={l,r,1,1,1};
37         return;
38     }
39     t[p]={l,r,0,0,0};
40     int mid=l+r>>1;
41     if(l<=mid)build(l,mid,p<<1);
42     if(r>mid)build(mid+1,r,p<<1|1);
43     t[p].ls=t[p].rs=t[p].m=t[p<<1].m+t[p<<1|1].m;
44 }
45 void update(int l,int c,int p){
46     if(t[p].l==t[p].r){
47         t[p].ls=t[p].rs=t[p].m=c;
48         //到达叶节点更新数据
49         return;
50     }
51     int mid=t[p].l+t[p].r>>1;
52     if(l<=mid)update(l,c,p<<1);
53     if(l>mid)update(l,c,p<<1|1);
54     up(p);
55 }
56 ll ask(int l,int p){
57     if(t[p].l==t[p].r||t[p].r-t[p].l+1==t[p].m||t[p].m==0){
58         return t[p].m;//如果到达叶子结点,或者这是一段完全连续的区间,或者这里被炸完了直接返回
59     }
60     int mid=t[p].l+t[p].r>>1;
61     ll sum=0;
62     if(l<=mid){
63         if(t[p<<1].r-(t[p<<1].rs-1)<=l)sum=t[p<<1].rs+ask(mid+1,p<<1|1);
64             //即查询的坑道在左边,且左段从右开始的连续坑道能覆盖查询坑道,这时直接加上t[p].rs,加上以mid+1作为目标点搜右半段的长度
65         else sum=ask(l,p<<1);
66         //否则目标坑道不变搜左段
67     }else if(l>mid){
68         if(t[p<<1|1].l+t[p<<1|1].ls-1>=l)sum=t[p<<1|1].ls+ask(mid,p<<1);
69             //即查询的坑道在右边,且右段从左开始的连续坑道能覆盖查询坑道,这时直接加上t[p].ls,加上以mid作为目标点搜左半段的长度
70         else sum=ask(l,p<<1|1);
71         //否则目标坑道不变搜右段
72     }
73     return sum;
74 }
75 stack<int>sk;
76 int main(){
77 //    freopen("in.txt","r",stdin);
78 //    freopen("out.txt","w",stdout);
79     while (~scanf("%d%d",&n,&m)) {
80         int x;
81         while (!sk.empty())sk.pop();
82         build(1, n, 1);
83         for (int i = 0; i < m; i++) {
84             scanf("%s", c);
85             if (c[0] == D) {
86                 scanf("%d", &x);
87                 sk.push(x);
88                 update(x,0, 1);
89             } else if (c[0] == Q) {
90                 scanf("%d", &x);
91                 printf("%lld\n", ask(x, 1));
92             } else {
93                 int tmp = sk.top();
94                 update(tmp,1, 1);
95                 sk.pop();
96             }
97         }
98     }
99 }

 

 

HDU1540线段树维护连续子区间

标签:abs   最大   turn   sdn   empty   signed   tran   数据   区间   

原文地址:https://www.cnblogs.com/ilikeeatfish/p/13938606.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!