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

hdu-4533(线段树+区间合并)

时间:2023-04-10 19:45:05浏览次数:59  
标签:hdu lc int 线段 tr 4533 rc include sum

约会安排

HDU - 4553

<iframe frameborder="0" height="2048px" id="frame-description" scrolling="no" src="https://vjudge.csgrandeur.cn/problem/description/1262434106?1565096932000" style="box-sizing: inherit; height: 1749.33px" width="100%"></iframe>

hdu-1540(线段树+区间合并) - 魏老6 - 博客园 (cnblogs.com)是一样,但是要写两个线段树。

线段树维护,最长前缀pre,最长后缀suf,以及最大连续连续区间sum。

1代表空,0代表时间被占了

还有几个注意事项:

当是DS时,只能查询和修改屌丝树;

当是NS时,先判断屌丝树能不能修改,能的话,屌丝和女神都要修改;屌丝树不能修改,则判断女神树能不能修改,能的话俩棵树都要修改。

详细见代码:

#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 100000
#define MAXN 310000
#define N 110010
#define M 1e9+7
#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, pre, suf,sum,tag;
}tr_1[N*4],tr_2[N*4];
int t, n, m;
void pushup(tree tr[],int p)
{
	int len = tr[p].r - tr[p].l +1;
	tr[p].sum = tr[lc].suf + tr[rc].pre;
	tr[p].pre = tr[lc].pre;
	tr[p].suf = tr[rc].suf;
	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));  //tr[p].sum 在中间连续的区间和左右结点的sum取最大
}
void pushdown(tree tr[], int p)
{
	
		if (tr[p].tag == 1)    //1代表学习,即有时间
		{
			tr[lc].pre = tr[lc].suf = tr[lc].sum = tr[lc].r - tr[lc].l + 1;
			tr[rc].pre = tr[rc].suf = tr[rc].sum = tr[rc].r - tr[rc].l + 1;
			tr[lc].tag = tr[rc].tag = 1;
			tr[p].tag = 0;
		}
		else if(tr[p].tag==-1)//-1代表时间被占
		{
			tr[lc].pre = tr[lc].suf = tr[lc].sum = 0;
			tr[rc].pre = tr[rc].suf = tr[rc].sum = 0;
			tr[lc].tag = tr[rc].tag = -1;
			tr[p].tag = 0;
		}
}
void build(tree tr[], int p, int l, int r)
{
	tr[p].tag = 0;   //我是sb,这里一定要写
	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(tr, lc, l, m);
	build(tr, rc, m + 1, r);
	pushup(tr,p);
}
void update(tree tr[], int p, int x, int y, int c)  //区间修改
{
	if (x <= tr[p].l && tr[p].r <= y)
	{
		if (c==1)
		{ 
			tr[p].pre = tr[p].suf = tr[p].sum = tr[p].r - tr[p].l + 1;
			tr[p].tag = 1;
		}
		else
		{
			tr[p].pre = tr[p].suf = tr[p].sum = 0;
			tr[p].tag = -1;
		}
		return;
	}
	pushdown(tr, p);
	int m = tr[p].l + tr[p].r >> 1;
	if (x <= m)update(tr, lc, x, y, c);
	if (y > m)update(tr, rc, x, y, c);
	pushup(tr, p);
}
int query(tree tr[], int p, int x)
{
	if (tr[p].l == tr[p].r)return tr[p].l;
	pushdown(tr,p);
	int m = tr[p].l + tr[p].r >> 1;
	if (tr[lc].sum >= x)return query(tr, lc, x);   //左边有,走左边
	else if (tr[lc].suf+tr[rc].pre>=x)return tr[lc].r - tr[lc].suf+1;  //左边没有,判断中间是否有
	else return query(tr, rc, x); //实在不行走右边
}
int main()
{
	int cnt = 0;
	t = read();
	while (t--)
	{
		cnt++;
		n = read(), m = read();
		build(tr_1, 1, 1, n);
		build(tr_2, 1, 1, n);
		printf("Case %d:\n", cnt);
		while (m--)
		{
			string s;
			cin >> s;
			if (s == "DS")
			{
				int x = read();
				if (tr_1[1].sum >= x)
				{
					int ans = query(tr_1, 1, x);
					printf("%d,let's fly\n", ans);
					update(tr_1, 1, ans, ans + x - 1, -1);
				}
				else puts("fly with yourself");
			}
			else if (s == "NS")
			{
				int x = read();
				if (tr_1[1].sum >= x)
				{
					int ans = query(tr_1, 1, x);
					printf("%d,don't put my gezi\n", ans);
					update(tr_1, 1, ans, ans + x - 1, -1);
					update(tr_2, 1, ans, ans + x - 1, -1);
				}
				else if (tr_2[1].sum >= x)
				{
					int ans = query(tr_2, 1, x);
					printf("%d,don't put my gezi\n", ans);
					update(tr_1, 1, ans, ans + x - 1, -1);
					update(tr_2, 1, ans, ans + x - 1, -1);
				}
				else puts("wait for me");
			}
			else
			{
				int x = read(), y = read();
				update(tr_1, 1, x, y, 1);
				update(tr_2, 1, x, y, 1);
				puts("I am the hope of chinese chengxuyuan!!");
			}
		}
	}
	return 0;
}

标签:hdu,lc,int,线段,tr,4533,rc,include,sum
From: https://www.cnblogs.com/wyh344866/p/17304083.html

相关文章

  • 可持久化线段树(主席树)
              代码#include<bits/stdc++.h>usingnamespacestd;constintN=4e7+10;intn,m,t,top,rt,mode,x,y;intf[N],a[N],root[N];structkkk{intl,r,val;}tree[N];intclone(intnode){top++;tree[top]=tree[node];return......
  • poj-3367(线段树+区间合并)
    HotelPOJ-3667思路:与hdu-1540(线段树+区间合并)-魏老6-博客园(cnblogs.com)类似,只不过是区间修改,多维护一个最大连续区间sum。#define_CRT_SECURE_NO_WARNINGS1#include<algorithm>#include<fstream>#include<iostream>#include<cstdio>#include<deque>#includ......
  • 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}\)为左端点......
  • HDU - 3572 Task Schedule (最大流)
    题目大意:有N个任务,M台机器。每个任务有相应的起始时间,截至时间和完成时间每台机器一小时可以做1个单位的工作量,每个任务的完成可以不连续,但每次只能由一台机器完成问能否完成所有任务解题思路:因为只有500分钟,所以可以将每分钟都设成1条边,连向超级汇点,容量为M每个任务连接向......
  • HDU - 3338 Kakuro Extension(最大流 行列模型)
    题目大意:看一下图基本就知道了解题思路:难点是构图。。设置一个超级源点和所有的行的和相连,容量为该行的和-该行和由几个数相加得到,因为这里将0看成了,1看成了2,依此类推设置一个超级汇点,和所有列的和相连,容量为该列的和-该列和由几个数相加得到,和上面一样接着就是空白部分......
  • HDU - 3081 Marriage Match II(二分图最大匹配 + 并查集)
    题目大意:有n个男生n个女生,现在要求将所有的男女配对,所有的男女都配对的话,算该轮游戏结束了。接着另一轮游戏开始,还是男女配对,但是配对的男女不能是之前配对过的。问这游戏能玩多少轮男女能配对的条件如下1.男女未曾吵架过。2.如果两个女的是朋友,那么另一个女的男朋友可以和......
  • HDU - 3715 Go Deeper (二分 + 2-SAT)
    题目大意:给出一个递归函数,问这个递归函数最多能递归几层解题思路:二分枚举递归层数,然后依此建边如果给出的c[i]为0时,那么x[a[i]]和x[b[i]]中的其中一个要为真,连边即为!a[i]->b[i],!b[i]->a[i]如果给出的c[i]为1时,那么x[a[i]]和x[b[i]]两个要么都为真,要么都为假,连边即为a[i]->b[i......
  • HDU - 1317 XYZZY (floyd + 最长路)
    题目大意:有一种游戏,游戏里面有N个房间,每个房间有相应的能量值,走入该房间就可以得到相应的能量值现在你要从房间1出发,走到房间N,如果中途能量耗尽了,就表示输了,反之,则为赢解题思路:首先得判断一下能不能到达N,这可以用Floyd去判断如果能直接走到N的话,就算赢,否则判断一下,看是否有正环......
  • HDU 5479 Scaena Felix(DP)
    题目大意:给出一系列的由’(‘和’)’组成的字符串,现有一种操作,可以将括号的方向变反,但需要花费1现在问,需要花费多少的代价才能使该字符串的任意一个连续子串都不存在”()”的配对解题思路:用dp[i][0]表示第i个位置变成’(‘的代价,dp[i][1]表示第i个位置变成’)’的代价如果当前......