[题解](线段树最大连续子段和)POJ_3667_Hotel

题意:1.求一个最靠左的长x的区间全部为0,并修改为1,输出这个区间的左端点

2.修改一个区间为0

实际上是维护最大连续子段和,原来也写过

大概需要维护一个左/右最大子段和,当前这段最大子段长,再维护一个lazytag

#include<iostream>
#include<cstdio>
#include<cstring>
#define mid (l+r>>1)
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int maxn=50009;
struct node{
    int l,r,mx,tg;//0全空,1全满,-1没有
}t[maxn<<2];
//inline void upd(int x,int l,int r){
//    t[x].l=t[ls].l;
//    t[x].r=t[rs].r;
////    if(t[ls].l==mid-l+1)t[x].l+=t[rs].l;
////    if(t[rs].r==r-mid)t[x].r+=t[ls].r;
//    if(t[ls].l==(r-l+1-(r-l+1)/2))t[x].l+=t[rs].l;
//    if(t[rs].r==(r-l+1)/2)t[x].r+=t[ls].r;
//    t[x].mx=max(max(t[ls].mx,t[rs].mx),t[ls].r+t[rs].l);
//}
//inline void pushdown(int x,int l,int r){
//    if(t[x].tg!=-1){
//        t[ls].tg=t[rs].tg=t[x].tg;
//        t[ls].l=t[ls].r=t[ls].mx=(r-l+1-(r-l+1)/2)*t[x].tg;
//        t[rs].l=t[rs].r=t[rs].mx=(r-l+1)/2*t[x].tg;
////        if(t[x].tg==0){
////            t[ls].l=t[ls].r=t[ls].mx=mid-l+1;
////            t[rs].l=t[rs].r=t[rs].mx=r-mid;
////        }
////        else{
////            t[ls].l=t[ls].r=t[ls].mx=0;
////            t[rs].l=t[rs].r=t[rs].mx=0;
////        }
//        t[x].tg=-1;
//    }
//}
inline void pushdown(int x,int len){
    if(t[x].tg!=-1){
        t[ls].tg=t[rs].tg=t[x].tg;
        t[ls].mx=t[ls].l=t[ls].r=t[x].tg*(len-(len>>1));
        t[rs].mx=t[rs].l=t[rs].r=t[x].tg*(len>>1);
        t[x].tg=-1;
    }
}
inline void upd(int x,int len){
    t[x].l=t[ls].l;
    t[x].r=t[rs].r;
    if(t[x].l==len-(len>>1))t[x].l+=t[rs].l;
    if(t[x].r==(len>>1))t[x].r+=t[ls].r;
    t[x].mx=max(max(t[ls].mx,t[rs].mx),t[ls].r+t[rs].l);
}
void build(int x,int l,int r){
    t[x].l=t[x].r=t[x].mx=r-l+1;t[x].tg=-1;
    if(l==r)return;
    build(ls,l,mid);build(rs,mid+1,r);
}
void change(int x,int l,int r,int L,int R,int k){
    if(L<=l && r<=R){
        t[x].l=t[x].r=t[x].mx= k==0?0:r-l+1;
        t[x].tg=k;
        return;
    }
//    pushdown(x,l,r);
    pushdown(x,r-l+1);
    if(L<=mid)change(ls,l,mid,L,R,k);
    if(R>mid)change(rs,mid+1,r,L,R,k);
//    upd(x,l,r);
    upd(x,r-l+1);
}
int query(int x,int l,int r,int k){
    if(l==r)return 1;
//    pushdown(x,l,r);
    pushdown(x,r-l+1);
    if(t[ls].mx>=k)return query(ls,l,mid,k);
    else if(t[ls].r+t[rs].l>=k)return mid-t[ls].r+1;
    else return query(rs,mid+1,r,k);
}
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1,op,x,y;i<=m;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&x);
            if(t[1].mx<x)printf("0\n");
            else{
                int pos=query(1,1,n,x);
                printf("%d\n",pos);
                change(1,1,n,pos,pos+x-1,0);
            }
        }
        else{
            scanf("%d%d",&x,&y);
            change(1,1,n,x,x+y-1,1);
        }
    }
}

原文地址:https://www.cnblogs.com/superminivan/p/11025449.html

时间: 2024-10-10 17:52:01

[题解](线段树最大连续子段和)POJ_3667_Hotel的相关文章

POJ2182题解——线段树

POJ2182题解——线段树 2019-12-20 by juruoOIer 1.线段树简介(来源:百度百科) 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩. 2.线段树实际应用 上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有

codedecision P1112 区间连续段 题解 线段树

题目描述:https://www.cnblogs.com/problems/p/P1112.html 题目链接:http://codedecision.com/problem/1112 线段树区间操作,每一个线段对应的点包含三个信息: \(l\):表示这个区间最左边的点的数值: \(r\):表示这个区间最右边的点的数值: \(cnt\):表示这个区间有多少个数值段. 合并的时候: 根节点的 \(l\) 值等于左儿子节点的 \(l\) 值: 根节点的 \(r\) 值等于右儿子节点的 \(r\) 值

理想乡题解 (线段树优化dp)

题面 思路概述 首先,不难想到本题可以用动态规划来解,这里就省略是如何想到动态规划的了. 转移方程 f[i]=min(f[j]+1)(max(i-m,0)<=j<i 且j符合士兵限定) 注意要用 max(i-m,0)以防止越界 我们先用两个数组sl,sa分别统计1~i个士兵中有多少个Lencer和Archer 然后在max(i-m,0)中寻找符合条件的j (1).两种士兵相差不超过k. 这个好说abs((sl[i]-sl[j])-(sa[i]-sa[j]))<=k 不要忘了第二种情况!!

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了.然后建线段树,线段树维护四个值: 1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记 2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最

[题解]线段树专题测试2017.1.21

很单纯的一道线段树题.稍微改一下pushDown()就行了. Code(线段树模板竟然没超100行) 1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cctype> 8 #include<queue> 9

Vijos1448题解---线段树+括号法

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作 输出格式 对于每个k=2输出一个答案 样例输入 5 4 1 1 3 2 2 5 1 2 4 2 3 5

HDU1540(线段树统计连续长度)

---恢复内容开始--- Tunnel Warfare Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Genera

模板——线段树维护最大子段和 SP1716 GSS3 - Can you answer these queries III

${\color{Pink}{>>Question}}$ 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #define ll long long 7 using namespace std; 8 9 template <typename T> void in

HDU 6155 Subsequence Count(矩阵 + DP + 线段树)题解

题意:01串,操作1:把l r区间的0变1,1变0:操作2:求出l r区间的子序列种数 思路:设DP[i][j]为到i为止以j结尾的种数,假设j为0,那么dp[i][0] = dp[i - 1][1] + dp[i -1][0] (0结尾新串) + dp[i - 1][0] (0结尾旧串) - dp[i - 1][0] (重复) + 1(0本身被重复时去除). 那么可以得到转移时的矩阵 $$ \left( \begin{matrix} dp[i - 1][0] & dp[i - 1][1] &am