zoukankan      html  css  js  c++  java
  • JZOJ 6943. 【2020.01.05冬令营模拟】社会实践(线段树)

    JZOJ 6943. 【2020.01.05冬令营模拟】社会实践

    题解

    • 题目的原型还是汉诺塔问题,操作规则和普通汉诺塔问题是一样的,先考虑对于某个单独询问如何计算最优答案。
    • 按普通汉诺塔,考虑还原的过程,发现根本不知道下一步该如何移动,无法解决,
    • 但如果从还原好的状态倒推,每一步移动都是自然的,初始所有圆盘都在最大圆盘应回到的柱子,然后从大到小,如果第 i i i个已复位则忽略, 否则将剩下 i − 1 i-1 i1个移到第三根柱,再移动第 i i i个,步数为 2 i − 1 2^{i-1} 2i1。这样移动可以保证时刻都是合法的。
    • 感觉这种过程很像可以用什么东西一段一段地维护,既然需要维护修改,那么想到线段树。
    • 因为初始位置不确定,所以每个位置需要记录当前段从任意一个柱子开始的最终步数和终止位置,合并时找到右儿子的终止位置作为左儿子的起点来查找即可。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 300010
    #define ll long long
    #define md 998244353
    int a[N], e[N];
    struct node {
    	ll s, x;
    }f[N * 4][4];
    void make(int v, int l, int r) {
    	if(l == r) {
    		f[v][1].x = 6 - a[l] - 1, f[v][2].x = 6 - a[l] - 2, f[v][3].x = 6 - a[l] - 3;
    		f[v][a[l]].x = a[l];
    		f[v][1].s = f[v][2].s = f[v][3].s = 1;
    		f[v][a[l]].s = 0;
    	}
    	else {
    		int mid = (l + r) / 2;
    		make(v * 2, l, mid), make(v * 2 + 1, mid + 1, r);
    		for(int i = 1; i < 4; i++) {
    			f[v][i].x = f[v * 2][f[v * 2 + 1][i].x].x;
    			f[v][i].s = (f[v * 2 + 1][i].s * e[mid - l + 1] + f[v * 2][f[v * 2 + 1][i].x].s) % md;
    		}
    	}
    }
    void ins(int v, int l, int r, int x, int c) {
    	if(l == r) {
    		f[v][1].x = 6 - a[l] - 1, f[v][2].x = 6 - a[l] - 2, f[v][3].x = 6 - a[l] - 3;
    		f[v][a[l]].x = a[l];
    		f[v][1].s = f[v][2].s = f[v][3].s = 1;
    		f[v][a[l]].s = 0;
    	}
    	else {
    		int mid = (l + r) / 2;
    		if(x <= mid) ins(v * 2, l, mid, x, c); else ins(v * 2 + 1, mid + 1, r, x, c);
    		for(int i = 1; i < 4; i++) {
    			f[v][i].x = f[v * 2][f[v * 2 + 1][i].x].x;
    			f[v][i].s = (f[v * 2 + 1][i].s * e[mid - l + 1] + f[v * 2][f[v * 2 + 1][i].x].s) % md;
    		}
    	}
    }
    node find(int v, int l, int r, int x, int y, int c) {
    	if(l == x && r == y) return f[v][c];
    	int mid = (l + r) / 2;
    	if(y <= mid) return find(v * 2, l, mid, x, y, c);
    	if(x > mid) return find(v * 2 + 1, mid + 1, r, x, y, c);
    	node t = find(v * 2 + 1, mid + 1, r, mid + 1, y, c);
    	node t1 = find(v * 2, l, mid, x, mid, t.x);
    	return {(t.s * e[mid - x + 1] + t1.s) % md, t1.x}; 
    }
    int main() {
    	int n, Q, i;
    	scanf("%d%d", &n, &Q);
    	for(i = 1; i <= n; i++) scanf("%d", &a[i]);
    	e[0] = 1;
    	for(i = 1; i <= n; i++) e[i] = e[i - 1] * 2 % md;
    	make(1, 1, n);
    	while(Q--) {
    		int op, x, y;
    		scanf("%d%d%d", &op, &x, &y);
    		if(op == 1) {
    			a[x] = y;
    			ins(1, 1, n, x, y);
    		}
    		else {
    			printf("%lld
    ", find(1, 1, n, x, y, a[y]).s);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    centos7 yum安装配置Lnmp和负载配置
    Linux搭建lamp(Apache+PHP+Mysql环境)centos7.2版详细教程
    php的移位符运算
    Mysql的注入与防御
    介绍10个非常有用的PHP函数
    PHP性能的分析
    Netty 4源码解析:服务端启动
    centOS6.6升级gcc4.8
    kafka 0.8.x producer Example(scala)
    spark standalone zookeeper HA部署方式
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279479.html
Copyright © 2011-2022 走看看