首页 > 其他分享 >poj-3367(线段树+区间合并)

poj-3367(线段树+区间合并)

时间:2023-04-08 15:55:18浏览次数:44  
标签:suf lc int 线段 3367 tr poj rc include

Hotel

POJ - 3667

思路:与hdu-1540(线段树+区间合并) - 魏老6 - 博客园 (cnblogs.com)类似,只不过是区间修改,多维护一个最大连续区间sum。

#define _CRT_SECURE_NO_WARNINGS 1
#include<algorithm>
#include<fstream>
#include<iostream>
#include<cstdio>
#include<deque>
#include<string>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
//#include<unordered_map>
using namespace std;
#define INF 2e9
#define MAXN 310000
#define N 1000100
#define M 10007
#define endl '\n'
#define exp 1e-8
#define lc p << 1
#define rc p << 1|1
#define lowbit(x) ((x)&-(x))
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
inline ULL read() {
	ULL x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
void print(ULL x) {
	if (x > 9)print(x / 10);
	putchar(x % 10 ^ 48);
}
struct tree
{
	int l, r, sum, pre, suf,tag;  //sum最大连续区间长度,pre最长前缀区间长度,suf最长后缀区间长度,tag标记
}tr[4*N];
int n, m;
void pushup(int p)
{
	int len = tr[p].r - tr[p].l + 1;
	tr[p].pre = tr[lc].pre;
	tr[p].suf = tr[rc].suf;
	tr[p].sum = tr[lc].suf + tr[rc].pre;
	if (tr[lc].pre == len - (len >> 1))
	{
		tr[p].pre = tr[lc].pre + tr[rc].pre;
	}
	if (tr[rc].suf == len >> 1)
	{
		tr[p].suf = tr[lc].suf + tr[rc].suf;
	}
	tr[p].sum = max(tr[p].sum, max(tr[lc].sum, tr[rc].sum));  //在左边,右边,中间取最大值
}
void pushdown(int p)  //下传标记, tag==1 为退房,-1为开房
{
	if (tr[p].tag == 1)
	{
		int len = tr[lc].r - tr[lc].l + 1;
		tr[lc].pre = tr[lc].suf = tr[lc].sum = len;
		len = tr[rc].r - tr[rc].l + 1;
		tr[rc].pre = tr[rc].suf = tr[rc].sum = len;
		tr[lc].tag = 1;
		tr[rc].tag = 1;
		tr[p].tag = 0;
	}
	else if (tr[p].tag == -1)
	{
		tr[lc].pre = tr[lc].suf = tr[lc].sum = 0;
		tr[rc].pre = tr[rc].suf = tr[rc].sum = 0;
		tr[lc].tag = -1;
		tr[rc].tag = -1;
		tr[p].tag = 0;
	}
}
void build(int p, int l, int r)
{
	tr[p].tag = 0;
	tr[p].l = l, tr[p].r = r;
	if (l == r)
	{
		tr[p].pre = tr[p].suf = tr[p].sum = 1;
		return;
	}
	int m = l + r >> 1;
	build(lc, l, m);
	build(rc, m + 1, r);
	pushup(p);
}
void update(int p,int x,int y,int k)
{
	if (x <= tr[p].l && tr[p].r <= y)
	{
		int len = tr[p].r - tr[p].l + 1;
		if (k == 1)
		{
			tr[p].pre = tr[p].suf = tr[p].sum = len;
			tr[p].tag = 1;
		}
		else
		{
			tr[p].pre = tr[p].suf = tr[p].sum = 0;
			tr[p].tag = -1;
		}
		return;
	}
	pushdown(p);
	int m = tr[p].l + tr[p].r >> 1;
	if (x <= m)update(lc, x, y, k);
	if (y > m)update(rc, x, y, k);
	pushup(p);
}
int query(int p,int m)  
{
	if (tr[p].l == tr[p].r)return tr[p].l; 
	pushdown(p);
	int mid = tr[p].r + tr[p].l >> 1;
	if (tr[lc].sum >= m)return query(lc, m);       //如果左边有大于m间房,走左边
	if (tr[lc].suf + tr[rc].pre >= m)return mid - tr[lc].suf + 1;  //如果中间连续取件大于m,返回左端点
	else return query(rc, m);    //走右边
}
int main()
{
	n = read(), m = read();
	build(1, 1, n);
	while (m--)
	{
		int op = 0, x = 0, y = 0;
		op = read(), x = read();
		if (op == 1)
		{
			if (tr[1].sum >= x)
			{
				int k = query(1, x);
				update(1, k, k + x - 1, -1);
				printf("%d\n", k);
			}
			else puts("0");
		}
		else
		{
			y = read();
			update(1, x, x + y - 1, 1);
		}
	}
	return 0;
}

标签:suf,lc,int,线段,3367,tr,poj,rc,include
From: https://www.cnblogs.com/wyh344866/p/17298647.html

相关文章

  • hdu-1540(线段树+区间合并)
    TunnelWarfareHDU-1540思路:没被摧毁的村庄为1,否则为0,用len记录线段树维护区间的两个信息:前缀最长1的序列pre后缀最长1的序列suf父节点与左右子节点的关系://lc为左节点,rc为右节点1.若左右结点都不满1,则tr[p].pre=tr[lc].pre,tr[p].suf=tr[rc].suf2.若左节点满1,tr......
  • [蓝桥杯 2021 国 AB] 翻转括号序列(线段树上二分)
    [蓝桥杯2021国AB]翻转括号序列题目描述给定一个长度为\(n\)的括号序列,要求支持两种操作:将\(\left[L_{i},R_{i}\right]\)区间内(序列中的第\(L_{i}\)个字符到第\(R_{i}\)个字符)的括号全部翻转(左括号变成右括号,右括号变成左括号)。求出以\(L_{i}\)为左端点......
  • POJ - 2029 Get Many Persimmon Trees(暴力水题)
    题目大意:给你一个矩阵,矩阵上面有N个柿子树,现在要求你画一个s*t的矩阵,使得这个矩阵内的柿子树达到最多解题思路:100*100,直接暴力#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;constintN=110;intn,w,h,s,t;intmap[N][N];voidin......
  • POJ - 1651 Multiplication Puzzle(区间dp)
    题目大意:给你N个数,每次可以选择一个数进行剔除(第一个和最后一个不能选择),选出该数后,sum+=该数左边的数*该数*该数右边的数问最小的sum是多少解题思路:用dp[i][j]表示[i,j]区间被剔除得只剩下i,j的最小sumdp[i][j]=dp[i][k]+dp[k][j]+num[i]*num[k]*num[j]#include......
  • POJ - 2955 Brackets(区间dp)
    题目大意:给出一个括号字符串,问这个字符串中符合规则的最长子串的长度解题思路:区间dp,用dp[i][j]表示[i,j]这个区间内有符合规则的最长子串的长度如果str[i]和str[j]能构成()或者[],那么dp[i][j]=dp[i+1][j-1]+2剩下的情况就是dp[i][j]=max(dp[i][j],dp[i][k]+dp[k......
  • POJ - 3666 Making the Grade(DP)
    题目大意:给你一个数组A,要求将这个数组变成数组B,使得Sum(abs(A[i]-B[i]))达到最小,且B是单调的解题思路:因为答案要求输出单调非递增或者单调非递减的的任意一个,那就只考虑单调非递增吧,因为两个的思路是相同的如果要变化的话,且变化的值要达到最小的话,那么只能变成和前一个相同或者......
  • POJ - 3186 Treats for the Cows(DP)
    题目大意:给你一个数组,每次你可以取两个数中的一个进行操作,要么取数组的第一个,要么数组的最后一个(取完之后,该数删除)假设取出来的数组组成了A现在要求使Sum=A[1]*1+A[2]*2+A[3]*3…+A[n]*n达到最大解题思路:用dp[i][j]表示前面取了i个,后面取了j个最大值则转......
  • POJ - 1661 Help Jimmy(DP)
    题目大意:中文题解题思路:因为是垂直下降,所以就可以将问题转变成从降落的平台到地面的最小时间因为只能从平台的左边或者右边才可以离开平台,所以可以分别计算出从左边和从右边到达地面的最短时间,并记录#include<cstdio>#include<cstring>#include<algorithm>usingnamespace......
  • POJ - 3616 Milking Time(DAG)
    题目大意:给出N头牛的产奶时间段和产奶量,每接完一头牛的奶后,需要休息R分钟问如何选择牛,才能使接到的产奶量达到最大解题思路:DAG,按产奶的结束时间大小排序#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;constintN=1010;structInterval{......
  • CAD如何测量连续线段长度?CAD测量连续线段长度步骤
    在CAD绘图过程中,经常会绘制一些连续的线段,如果想要知道这些连续线段长度的话,该怎么操作吗?CAD如何测量连续线段长度?下面小编就以浩辰CAD软件为例来给大家分享一下CAD测量连续线段长度的具体操作步骤吧!CAD测量连续线段长度步骤:浩辰CAD软件中已经考虑到了这种需求,在CAD测量命令(DIST......