`
digiter
  • 浏览: 120433 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

HDU 3397 Sequence operation

    博客分类:
  • ICPC
阅读更多
这道题又做得颇有感触...线段树好像总是很灵活,不过我觉得它应该也是有章可循的
这次用自己配的gvim写,感觉还不错
这次还学到一点技巧,就是无限WA时可以写个暴力程序对拍,对于这道题虽然没法一步一步跟踪数据,但是这样的对拍还是给了我许多启发

线段树应该记录cover表示当前节点是否覆盖,以及覆盖的类型
然后还是三部曲:进入子节点之前分配信息,递归调用子节点,从子节点回来合并信息


/*
 * Author: rush
 * Created Time:  2010年05月01日 星期六 15时17分10秒
 * File Name: icpc/hdu/3397.cpp
 */
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using std::swap;
using std::max;

int max3(int a, int b, int c)
{ return max(a, max(b, c)); }
int max4(int a, int b, int c, int d)
{ return max(a, max3(b, c, d)); }

const int size = 100000 + 5;
struct node_t {
	int L0, M0, R0;
	int L1, M1, R1;
	int ONE;
	int range;
	int cover; // 覆盖情况(-1是未覆盖,0, 1, 2如题) 
	void reset(const int _r)
	{
		range = _r;
		L0 = M0 = R0 = range;
		L1 = M1 = R1 = 0;
		ONE = 0;
	}
	void perform(int op)
	{
		switch (op) {
		case 0: 
			L0 = M0 = R0 = range;
			L1 = M1 = R1 = 0;
			ONE = 0;
			cover = 0;
			break;
		case 1:
			L0 = M0 = R0 = 0;
			L1 = M1 = R1 = range;
			ONE = range;
			cover = 1;
			break;
		case 2:
			swap(L0, L1), swap(M0, M1), swap(R0, R1);
			ONE = range - ONE;
			// 这里很关键,根据之前的覆盖情况确定现在的覆盖情况,
			// 其实对于case 0和case 1也有这个问题,不过因为是直接改变最终值为0或1,
			// 而不是像case 2这样根据之前情况改变,所以那里没有这样分情况处理 
			switch (cover) { 
			case -1:
				cover = 2; break;
			case 0:
				cover = 1; break;
			case 1:
				cover = 0; break;
			case 2:
				cover = -1; break;
			}
			break;
		}
	}
} tree[size * 3];
int n, m;

void plant(int low, int high, int node)
{
	tree[node].reset(high - low + 1);
	tree[node].cover = -1;
	int mid = (low + high) / 2;
	// low < high 恰好能够处理[x, x]的区间(即对于单个点构成的区间) 
	if (low < high)
	{
		plant(low, mid, node * 2);
		plant(mid + 1, high, node * 2 + 1);
	}
}

int left, right;
void update(int low, int high, int node, int op)
{
	if (left <= low && high <= right) {
		tree[node].perform(op);
	} else if (left <= high && low <= right) {
		int mid = (low + high) / 2;
		// 进入递归前,如果当前结点被覆盖,则将其属性传递给子节点 
		if (tree[node].cover != -1)
		{
			tree[node * 2].perform(tree[node].cover);
			tree[node * 2 + 1].perform(tree[node].cover);
			tree[node].cover = -1;
		}
		// 递归调用左右子节点,这里不用判断low < high是因为如果有单点区间,
		// 则单点一定会被本函数的第一个if考虑到 
		update(low, mid, node * 2, op);
		update(mid + 1, high, node * 2 + 1, op);
		// 从左右子节点回来,更新父节点的信息
		node_t &pnt = tree[node], &lch = tree[node * 2], &rch = tree[node * 2 + 1];
		pnt.L0 = lch.L0 + (lch.L0 == lch.range ? rch.L0 : 0);
		pnt.M0 = max3(lch.M0, lch.R0 + rch.L0, rch.M0);
		pnt.R0 = rch.R0 + (rch.R0 == rch.range ? lch.R0 : 0);

		pnt.L1 = lch.L1 + (lch.L1 == lch.range ? rch.L1 : 0);
		pnt.M1 = max3(lch.M1, lch.R1 + rch.L1, rch.M1);
		pnt.R1 = rch.R1 + (rch.R1 == rch.range ? lch.R1 : 0);

		pnt.ONE = lch.ONE + rch.ONE;
	}
}
// 其实只需要记录询问的区间被拆成哪2 * log n个子区间就行了,
// 所以不按常规的做法,而是像我这样把它们标记出来也是一样的 
int a[32 * 2], la;
void query(int low, int high, int node)
{
	if (left <= low && high <= right) {
		a[la++] = node;
	} else if (left <= high && low <= right) {
		int mid = (low + high) / 2;
		// 查询时也需要将父节点信息传递给子节点,
		// 这是因为前面update函数只能保证从2*logn个子区间往上的信息是对的 
		// 往下的没有做更新(如果做了就是指数的复杂度了) 
		if (tree[node].cover != -1)
		{
			tree[node * 2].perform(tree[node].cover);
			tree[node * 2 + 1].perform(tree[node].cover);
			tree[node].cover = -1;
		}
		query(low, mid, node * 2);
		query(mid + 1, high, node * 2 + 1);
	}
}

int main()
{
	freopen("data.in", "r", stdin);
	freopen("my.out", "w", stdout);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &m);
		plant(0, n - 1, 1);
		int t;
		for (int i = 0; i < n; ++i)
		{
			scanf("%d", &t);
			left = right = i;
			update(0, n - 1, 1, t);
		}
		for (int i = 0; i < m; ++i)
		{
			scanf("%d%d%d", &t, &left, &right);
			if (t < 3) {
				update(0, n - 1, 1, t);
			} else {
				la = 0;
				query(0, n - 1, 1);
				if (t == 3) {
					int ans3 = 0;
					for (int j = 0; j < la; ++j)
						ans3 += tree[a[j]].ONE;
					printf("%d\n", ans3);
				} else {
					int ans4 = 0;
					for (int j = 0; j < la; ++j)
						ans4 = max(ans4, tree[a[j]].M1);
					int tmp = 0;
					for (int j = 0; j < la; ++j)
						if (tree[a[j]].ONE == tree[a[j]].range) {
							tmp += tree[a[j]].range;
						} else {
							tmp += tree[a[j]].L1;
							ans4 = max(ans4, tmp);
							tmp = tree[a[j]].R1;
						}
					ans4 = max(ans4, tmp);
					printf("%d\n", ans4);
				}
			}
		}
	}
    return 0;
}



分享到:
评论

相关推荐

    NumberSequence

    在IT行业中,"Number Sequence"通常指的是在特定系统或应用中用于生成自动递增或递减的数字序列。这些序列可以用于唯一标识记录、订单号、发票号等,确保数据的唯一性和可追踪性。在Microsoft Dynamics AX(现称为...

    zyq2652192993zyq#Advance-Algorithm#HDU-1711 Number Sequence(KMP算

    HDU-1711 Number Sequence(KMP算法)For each test case, you should output one line wh

    hdu.rar_hdu

    HDU(杭州电子科技大学在线评测系统)是一个深受程序员喜爱的在线编程练习平台,它提供了丰富的算法题目供用户挑战,帮助他们提升编程技能和算法理解能力。"hdu.rar_hdu"这个压缩包文件很可能是某位程序员整理的他在...

    HDU_2010.rar_hdu 2010_hdu 20_hdu acm20

    【标题】"HDU_2010.rar"是一个压缩包文件,其中包含了与"HDU 2010"相关的资源,特别是针对"HDU ACM20"比赛的编程题目。"hdu 2010"和"hdu 20"可能是该比赛的不同简称或分类,而"hdu acm20"可能指的是该赛事的第20届...

    HDU题目java实现

    【标题】"HDU题目java实现"所涉及的知识点主要集中在使用Java编程语言解决杭州电子科技大学(HDU)在线评测系统中的算法问题。HDU是一个知名的在线编程竞赛平台,它提供了大量的算法题目供参赛者练习和提交解决方案...

    HDU5667 Sequence

    《HDU5667 Sequence:递推序列的矩阵快速幂解决方案》 在解决计算机科学中的数学问题时,特别是涉及到大规模数值计算时,高效的算法至关重要。HDU5667 "Sequence" 这一问题就是一个典型的例子,它要求处理一个递推...

    ACM HDU题目分类

    ACM HDU 题目分类 ACM HDU 题目分类是指对 HDU 在线判题系统中题目的分类,总结了大约十来个分类。这些分类将有助于编程选手更好地理解和解决问题。 DP 问题 DP(Dynamic Programming,动态规划)是一种非常重要...

    hdu1250高精度加法

    ### hdu1250高精度加法 #### 背景介绍 在计算机科学与编程竞赛中,处理大整数运算(特别是加法、减法、乘法等)是常见的需求之一。当数字的位数超过了标准数据类型(如`int`、`long`等)所能表示的最大值时,就需要...

    HDU DP动态规划

    【标题】"HDU DP动态规划"涉及到的是在算法领域中的动态规划(Dynamic Programming,简称DP)技术,这是解决复杂问题的一种高效方法,尤其适用于有重叠子问题和最优子结构的问题。动态规划通常用于优化多阶段决策...

    HDU1059的代码

    HDU1059的代码

    hdu.rar_HDU 1089.cpp_OJ题求和_hdu_horsekw5_杭电obj

    【标题】"hdu.rar_HDU 1089.cpp_OJ题求和_hdu_horsekw5_杭电obj" 提供的信息是关于一个压缩文件,其中包含了一个名为 "HDU 1089.cpp" 的源代码文件,这个文件是为了解决杭州电子科技大学(Hangzhou Dianzi ...

    hdu1001解题报告

    hdu1001解题报告

    hdu 1574 passed sorce

    hdu 1574 passed sorce

    hdu2101解决方案

    hdu2101AC代码

    ACM HDU

    【ACM HDU】指的是在ACM(国际大学生程序设计竞赛,International Collegiate Programming Contest)中,参赛者在杭州电子科技大学(Hangzhou Dianzi University,简称HDU)的在线评测系统上完成并已解决的题目集合...

    杭电ACMhdu1163

    【标题】:杭电ACMhdu1163 【描述】:这是一道源自杭州电子科技大学(Hangzhou Dianzi University,简称HDU)的ACM编程竞赛题目,编号为1163。这类问题通常需要参赛者利用计算机编程解决数学、逻辑或算法上的挑战,...

    hdu 5007 Post Robot

    hdu 5007 Post Robot 字符串枚举。 暴力一下就可以了。

    Hdu1000—2169部分代码

    HDU是杭州电子科技大学(Hangzhou Dianzi University)举办的一个在线编程竞赛平台,全称为HDU Online Judge。ACM是国际大学生程序设计竞赛(International Collegiate Programming Contest)的缩写,是一个全球性的...

    【hdu5306】Gorgeous Sequence 线段树区间最值操作-附件资源

    【hdu5306】Gorgeous Sequence 线段树区间最值操作-附件资源

    HDU acm-PPT课件

    【ACM入门与提高:HDU ACM竞赛课程详解】 ACM(国际大学生程序设计竞赛,International Collegiate Programming Contest,简称ICPC或ACM/ICPC)是一项全球性的竞赛,旨在激发大学生对计算机科学的兴趣,提升他们的...

Global site tag (gtag.js) - Google Analytics