zoukankan      html  css  js  c++  java
  • HDU1540线段树维护连续子区间

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

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

    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
    ", ask(x, 1));
    92             } else {
    93                 int tmp = sk.top();
    94                 update(tmp,1, 1);
    95                 sk.pop();
    96             }
    97         }
    98     }
    99 }
     
  • 相关阅读:
    activity 背景透明
    win系统注册缺少的库 32位系统 64位系统
    android 窗
    wireshark抓包分析
    juqery select 标签
    IOS开发应用之Quartz 2D学习指南
    为什么你总会觉得自己的产品不够好
    日志宝
    Android之Inflate()方法用途+setContentView和inflate区别
    Ralasafe
  • 原文地址:https://www.cnblogs.com/ilikeeatfish/p/13938606.html
Copyright © 2011-2022 走看看