• hiho_1058_combination_lock


    题目大意

        给定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
    ", gSeq);
    		getchar();
    	}
    	Query(0);
    	printf("%s
    ", gSeq);
    	return 0;
    }
    
  • 相关阅读:
    spring cloud 网关
    spring cloud 熔断器
    spring cloud 健康检查
    spring cloud 分布式链路跟踪(集成zipkin)
    spring cloud 分布式链路追踪
    spring cloud eureka 微服务之间的调用
    spring cloud eureka注册中心
    ACCP8.0Y2Web前端框架与移动应用开发第5章Bootstrap制作微票儿首页
    ACCP8.0Y2Web前端框架与移动应用开发第4章Bootstrap的JavaScript插件
    ACCP8.0Y2Web前端框架与移动应用开发第3章Bootstrap组件
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/5538263.html
Copyright © 2020-2023  润新知