hiho_1058_combination_lock

news/2024/8/22 12:46:28

题目大意

    给定N个字符,范围为A-Z,编号为1-N,对该字符序列进行M个操作,操作有4中类型: 
(1)CMD 1 i j X 
    将[i, j]区间内的字符均变为X 
(2)CMD 2 i j K 
    将[i, j]区间内的字符均增加K,如果超过Z,则再从A开始循环。 
(3)CMD 3 K 
    将字符序列中最左端的K个字符移动到最右端 
(4)CMD 4 i j 
    进行一个递归操作: 
if i > j 
    return; 
else 
    CMD 4 i+1 j 
    CMD 2 i j 
endif

题目分析

    对区间进行操作,考虑使用线段树,CMD 1, 2很容易通过线段树解决,但是对于CMD 3,可以进行转换一下:CMD 3并不直接对线段树的叶子节点上的元素进行移动(复杂度太高),而是记录一个偏移量offset,当CMD 3之后再进行其他操作时,将其他操作的区间[i, j]映射到添加偏移量之后的区间[(i + offset)%N, (j + offset)%N],当然,如果 (i + offset)%N > (j + offset)%N,则需要分两个部分进行求解 [0, j]和[i, N-1]。在最后输出字符串时候,再根据最后的offset来定位到元素实际的位置。 
    对于CMD 4,可以发现它的实际效果是将[i, j]区间内的数字,s[i] + 1, s[i+2] + 2, s[i+2] + 3.... 那么,对于线段树的节点,维护一个delta和一个inc,delta表示该区间的首位元素由于CMD 4的操作需要增加的量为delta,而inc表示该区间相邻元素a1,a2由于CMD 4而使得a2比a1增加inc。 
    因此用线段树来求解时,用以下信息来记录线段树节点的状态: 
(1) value 默认为-1, 如果大于等于0,表示该节点代表的区间内的值均为 value 
(2) add 默认为0, 如果不等于0,表示该节点代表区间内的值均增加add 
(3) delta 默认为0,如果不等于0,表示该节点代表区间内最左端元素由于CMD 4需要增加的量 
(4) inc 默认为0,如果不为0,表示该节点代表区间内相邻元素之间增量相差inc.

实现

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
using namespace std;
#define MAX(a,b) (a > b? a:b)
#define MIN(a,b) (a < b? a:b)

struct Node {
	int beg, end;
	int value;	//该区间的所有值均为 'A' + value, 若value为-1,为无效
	int add;    //该区间所有的值均增加add
	int delta; //对应操作CMD4, 表示区间最左端的元素增加的数值
	int inc;	//对应操作CMD4, 表示区间从最左端到最右端当前元素比前一个元素增加的数值
	Node() {
		beg = end = add = delta = inc = 0;
		value = -1;
	}
};
char gSeq[50005];
Node gNodes[200005];
void BuildTree(int node, int beg, int end) {
	gNodes[node].beg = beg;
	gNodes[node].end = end;

	if (beg == end) {
		gNodes[node].value = gSeq[beg] - 'A';
		return;
	}
	int left = 2 * node + 1;
	int right = 2 * node + 2;
	int mid = (beg + end) / 2;
	BuildTree(left, beg, mid);
	BuildTree(right, mid + 1, end);
}
int gPoint = 0;
int N; //sequence length
void PushDown(int node) {
	if (gNodes[node].beg == gNodes[node].end) {
		return;
	}
	int left = 2 * node + 1, right = 2 * node + 2;
	if (gNodes[node].value >= 0) {
		//如果node的value大于0,说明之前曾经被赋值过,那么node的 add,delta,inc等如果不为0,则都是在赋值value之后
		//进行的操作
		gNodes[left].value = gNodes[right].value = gNodes[node].value;
		gNodes[left].add = gNodes[right].add = gNodes[node].add;
		gNodes[left].delta = gNodes[node].delta;
		gNodes[right].delta = (gNodes[left].end - gNodes[left].beg + 1)*gNodes[node].inc + gNodes[node].delta;
		gNodes[left].inc = gNodes[right].inc = gNodes[node].inc;
	}
	else{
		gNodes[left].add += gNodes[node].add;
		gNodes[right].add += gNodes[node].add;
		if (gNodes[node].delta){
			gNodes[left].delta += gNodes[node].delta;
			gNodes[right].delta += (gNodes[left].end - gNodes[left].beg + 1)*gNodes[node].inc + gNodes[node].delta;
			gNodes[right].inc += gNodes[node].inc;
			gNodes[left].inc += gNodes[node].inc;
		}
	}
	gNodes[node].value = -1;
	gNodes[node].add = gNodes[node].delta = gNodes[node].inc = 0;
}
void Action(int node, int beg, int end, int cmd, int k){
	if (beg > end)
		return;
	if (gNodes[node].beg == beg && gNodes[node].end == end){
		if (cmd == 1){
			gNodes[node].value = k;
			gNodes[node].add = gNodes[node].delta = gNodes[node].inc = 0;
		}
		else if (cmd == 2){
			gNodes[node].add += k;
		}
		else if (cmd == 4){
			gNodes[node].delta += k;
			gNodes[node].inc++;
		}
		return;
	}
	PushDown(node);
	int mid = (gNodes[node].beg + gNodes[node].end) / 2;
	int left = 2 * node + 1, right = 2 * node + 2;
	if (beg > mid){
		Action(right, beg, end, cmd, k);
	}
	else if (end <= mid){
		Action(left, beg, end, cmd, k);
	}
	else{
		Action(left, beg, mid, cmd, k);
		if (cmd == 4)
			k += mid - beg + 1;
		Action(right, mid + 1, end, cmd, k);
	}
}
void Query(int node) {
	if (gNodes[node].beg == gNodes[node].end) {
	int index = ((gNodes[node].beg - gPoint) % N + N) % N;
	gSeq[index] = 'A' + ((gNodes[node].value + gNodes[node].add + gNodes[node].delta) % 26 + 26) % 26;
	return;
	}
	int left = 2 * node + 1, right = 2 * node + 2;
	if (gNodes[node].value >= 0) {
	//如果node的value大于0,说明之前曾经被赋值过,那么node的 add,delta,inc等如果不为0,则都是在赋值value之后
	//进行的操作
	gNodes[left].value = gNodes[right].value = gNodes[node].value;
	gNodes[left].add = gNodes[right].add = gNodes[node].add;
	gNodes[left].delta = gNodes[node].delta;
	gNodes[right].delta = (gNodes[left].end - gNodes[left].beg + 1)*gNodes[node].inc + gNodes[node].delta;
	gNodes[left].inc = gNodes[right].inc = gNodes[node].inc;
	}
	else{
	gNodes[left].add += gNodes[node].add;
	gNodes[right].add += gNodes[node].add;
	if (gNodes[node].delta){
	gNodes[left].delta += gNodes[node].delta;
	gNodes[right].delta += (gNodes[left].end - gNodes[left].beg + 1)*gNodes[node].inc + gNodes[node].delta;
	gNodes[right].inc += gNodes[node].inc;
	gNodes[left].inc += gNodes[node].inc;
	}
	}
	gNodes[node].value = -1;
	gNodes[node].add = gNodes[node].delta = gNodes[node].inc = 0;
	Query(left);
	Query(right);

}


int main() {
	int  m;
	char tmp[5];
	int cmd, i, j, k;
	char c;
	scanf("%d %d", &N, &m);
	getchar();
	scanf("%s", gSeq);
	BuildTree(0, 0, N - 1);
	getchar();
	for (int t = 0; t < m; t++) {
		scanf("%s %d", tmp, &cmd);
		if (cmd == 1) {
			scanf("%d %d %c", &i, &j, &c);
			i = ((i - 1 + gPoint) % N + N) % N;
			j = ((j - 1 + gPoint) % N + N) % N;
			if (i > j) {
				Action(0, 0, j, 1, c - 'A');
				Action(0, i, N - 1, 1, c - 'A');
			}
			else
				Action(0, i, j, 1, c - 'A');
		}
		else if (cmd == 2) {
			scanf("%d %d %d", &i, &j, &k);
			i = ((i - 1 + gPoint) % N + N) % N;
			j = ((j - 1 + gPoint) % N + N) % N;
			if (i > j) {
				Action(0, 0, j, 2, k);
				Action(0, i, N - 1, 2, k);
			}
			else
				Action(0, i, j, 2, k);
		}
		else if (cmd == 3) {
			scanf("%d", &k);
			gPoint += k;
		}
		else if (cmd == 4) {
			scanf("%d %d", &i, &j);
			i = ((i - 1 + gPoint) % N + N) % N;
			j = ((j - 1 + gPoint) % N + N) % N;
			if (i > j) {
				Action(0, 0, j, 4, N - i + 1);
				Action(0, i, N - 1, 4, 1);
			}
			else
				Action(0, i, j, 4, 1);
		}
		//Query(0);
		//printf("%s\n", gSeq);
		getchar();
	}
	Query(0);
	printf("%s\n", gSeq);
	return 0;
}

 

转载于:https://www.cnblogs.com/gtarcoder/p/5538263.html


http://www.niftyadmin.cn/n/4051100.html

相关文章

团队项目:第二次冲刺站立会议02

团队项目&#xff1a;第二次冲刺站立会议02 一.昨天干了什么搜集各银行业务的相关资料&#xff0c;注意事项。二.今天准备干什么整理关于银行业务的相关资料&#xff0c;列出所要内容。三.遇到的困难整理资料没什么困难。转载于:https://www.cnblogs.com/kongyuhang/p/5538607.…

回收站删除的文件怎么恢复?清空也能恢复数据

回收站删除的文件怎么恢复&#xff1f;在平时使用电脑的过程中&#xff0c;我们都会时不时将无用的文件清理&#xff0c;甚至将回收站再次清空以节省空间&#xff0c;但有时候难免会发生这样的情况&#xff0c;就是删除的文件还需要再次用到&#xff0c;那怎么从清空的回收站中…

u盘提示格式化怎么办?分享数据恢复小妙招

u盘提示格式化怎么办&#xff1f;u盘是我们常用的一款小工具&#xff0c;但随着时间的积累&#xff0c;难免会存在一些小问题&#xff0c;比如u盘提示格式化&#xff0c;这是什么原因造成的呢&#xff1f;里面的数据还有机会恢复吗&#xff1f;别担心&#xff0c;下面就围绕这些…

硬盘坏了数据可以恢复吗?盘点数据恢复技巧

硬盘坏了数据可以恢复吗&#xff1f;硬盘是计算机中一项主要的存储设备&#xff0c;里面存储了很多重要的数据&#xff0c;但在长期的使用之下&#xff0c;硬盘很容易出现损坏的情况&#xff0c;从而导致数据丢失&#xff0c;恢复硬盘的方法自然是有的&#xff0c;但也要根据不…

删除的照片如何恢复?SD卡数据恢复妙招

删除的照片如何恢复&#xff1f; 生活中我们用到相机的机会很多&#xff0c;如果不小心删除了相机里面的照片有什么补救的方法吗&#xff1f;当然是有的&#xff0c;随着科技的进步&#xff0c;数据恢复软件的功能也越来越强大&#xff0c;下面就给大家分享一下相机照片恢复方法…

u盘文件损坏怎么恢复数据?数据恢复很简单

u盘文件损坏怎么恢复数据&#xff1f;u盘因其小巧、便于携带、性价比高等特点&#xff0c;成为了我们常用的一款移动存储设备&#xff0c;但使用久了u盘也会出现一些问题&#xff0c;如u盘插入电脑后打不开、文件系统损坏数据需要恢复&#xff0c;别担心&#xff0c;下面就给大…

回收站删除的文件怎么恢复?文件恢复妙招来了

回收站删除的文件怎么恢复&#xff1f;电脑回收站是我们用来存放临时删除文件的地方&#xff0c;只要不清空&#xff0c;删除的文件都可以从中直接还原&#xff0c;但有时候难免会遇到清空后还需要找回的情况&#xff0c;怎么恢复回收站呢&#xff1f;下面就来了解下回收站数据…

u盘插电脑上不显示怎么办?数据恢复还有希望吗

u盘插电脑上不显示怎么回事&#xff1f;日常生活中&#xff0c;我们常用u盘存储一些重要的资料&#xff0c;但有时候在使用u盘的时候会遇到u盘无法显示的情况&#xff0c;这是什么原因导致的&#xff1f;里面的数据是否还能找回呢&#xff1f;下面就来看看解决方法吧。 u盘盘符…