zoukankan      html  css  js  c++  java
  • 【洛谷3822】[NOI2017] 整数(线段树压位)

    题目:

    洛谷 3822

    分析:

    直接按题意模拟,完了。

    将每次加 / 减拆成不超过 (32) 个对单独一位的加 / 减。

    考虑给一个二进制位(下称「当前位」)加 (1) 时,如果这一位本来就是 (0) ,那么直接变成 (1) 。否则要考虑进位:向左(以后默认从右向左为低位至高位,与书写顺序相同)找到第一个为 (0) 的位 (p) ,将其变成 (1) ,并把从 (p) 到当前位中间所有的 (1) 变成 (0)

    减法是类似的。退位操作就是向左找到第一个 (1) ,将其变成 (0) ,并把中间所有 (0) 变成 (1)

    以上找第一个 (1) 或者 (0) 和区间修改均可用线段树完成,只需要维护每个结点对应的区间是否全 (0) 或全 (1) 即可。

    但是将一个询问拆成 (32) 次常数太大,(3.2 imes 10^7) 次修改再带上线段树的 (log 3 imes 10^7) 根本过不去。考虑压位,线段树每个叶子表示连续多个(我的代码中使用的是 (60) 个)二进制位,找第一个 (1) / (0) 改为找第一个非 (0) (全 (0) ) / 非 (2^{60}) (全 (1) )的数。这样,每次修改只需要拆成最多对两个位置的加 / 减。复杂度 (O(nlog m)) 其中 (m) 是最大位数。

    代码:

    注意线段树上二分找第一个非全 (0) / 非全 (1) 的数的做法。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    using namespace std;
    
    namespace zyt
    {
    	template<typename T>
    	inline bool read(T &x)
    	{
    		char c;
    		bool f = false;
    		x = 0;
    		do
    			c = getchar();
    		while (c != EOF && c != '-' && !isdigit(c));
    		if (c == EOF)
    			return false;
    		if (c == '-')
    			f = true, c = getchar();
    		do
    			x = x * 10 + c - '0', c = getchar();
    		while (isdigit(c));
    		if (f)
    			x = -x;
    		return true;
    	}
    	template<typename T>
    	inline void write(T x)
    	{
    		static char buf[20];
    		char *pos = buf;
    		if (x < 0)
    			putchar('-'), x = -x;
    		do
    			*pos++ = x % 10 + '0';
    		while (x /= 10);
    		while (pos > buf)
    			putchar(*--pos);
    	}
    	typedef unsigned long long ull;
    	const int N = 1e6 + 10, DIGIT = 60;
    	const ull BASE = 1ULL << DIGIT;
    	namespace Segment_Tree
    	{
    		struct node
    		{
    			ull val;
    			bool all0, all1, tag0, tag1;
    		}tree[N << 2];
    		void cov0(const int rot)
    		{
    			tree[rot].val = 0;
    			tree[rot].all0 = tree[rot].tag0 = true;
    			tree[rot].all1 = tree[rot].tag1 = false;
    		}
    		void cov1(const int rot)
    		{
    			tree[rot].val = BASE - 1ULL;
    			tree[rot].all1 = tree[rot].tag1 = true;
    			tree[rot].all0 = tree[rot].tag0 = false;
    		}
    		void update(const int rot)
    		{
    			tree[rot].all0 = (tree[rot << 1].all0 && tree[rot << 1 | 1].all0);
    			tree[rot].all1 = (tree[rot << 1].all1 && tree[rot << 1 | 1].all1);
    		}
    		void pushdown(const int rot)
    		{
    			if (tree[rot].tag0)
    			{
    				cov0(rot << 1), cov0(rot << 1 | 1);
    				tree[rot].tag0 = false;
    			}
    			else if (tree[rot].tag1)
    			{
    				cov1(rot << 1), cov1(rot << 1 | 1);
    				tree[rot].tag1 = false;
    			}
    		}
    		void cover0(const int rot, const int lt, const int rt, const int ls, const int rs)
    		{
    			if (ls <= lt && rt <= rs)
    			{
    				cov0(rot);
    				return;
    			}
    			int mid = (lt + rt) >> 1;
    			pushdown(rot);
    			if (ls <= mid)
    				cover0(rot << 1, lt, mid, ls, rs);
    			if (rs > mid)
    				cover0(rot << 1 | 1, mid + 1, rt, ls, rs);
    			update(rot);
    		}
    		void cover1(const int rot, const int lt, const int rt, const int ls, const int rs)
    		{
    			if (ls <= lt && rt <= rs)
    			{
    				cov1(rot);
    				return;
    			}
    			int mid = (lt + rt) >> 1;
    			pushdown(rot);
    			if (ls <= mid)
    				cover1(rot << 1, lt, mid, ls, rs);
    			if (rs > mid)
    				cover1(rot << 1 | 1, mid + 1, rt, ls, rs);
    			update(rot);
    		}
    		void change(const int rot, const int lt, const int rt, const int pos, const ull x)
    		{
    			if (pos > rt)
    				return;
    			if (lt == rt)
    			{
    				tree[rot].val = x;
    				tree[rot].all0 = (x == 0);
    				tree[rot].all1 = (x == (BASE - 1ULL));
    				return;
    			}
    			int mid = (lt + rt) >> 1;
    			pushdown(rot);
    			if (pos <= mid)
    				change(rot << 1, lt, mid, pos, x);
    			else
    				change(rot << 1 | 1, mid + 1, rt, pos, x);
    			update(rot);
    		}
    		ull query(const int rot, const int lt, const int rt, const int pos)
    		{
    			if (lt == rt)
    				return tree[rot].val;
    			int mid = (lt + rt) >> 1;
    			pushdown(rot);
    			if (pos <= mid)
    				return query(rot << 1, lt, mid, pos);
    			else
    				return query(rot << 1 | 1, mid + 1, rt, pos);
    		}
    		int find0(const int rot, const int lt, const int rt, const int pos)
    		{
    			if (lt == rt)
    				return lt;
    			int mid = (lt + rt) >> 1;
    			pushdown(rot);
    			if (pos <= mid && !tree[rot << 1].all1)
    			{
    				int ans = find0(rot << 1, lt, mid, pos);
    				if (ans <= N)
    					return ans;
    			}
    			if (!tree[rot << 1 | 1].all1)
    				return find0(rot << 1 | 1, mid + 1, rt, pos);
    			else
    				return N + 1;
    		}
    		int find1(const int rot, const int lt, const int rt, const int pos)
    		{
    			if (lt == rt)
    				return lt;
    			int mid = (lt + rt) >> 1;
    			pushdown(rot);
    			if (pos <= mid && !tree[rot << 1].all0)
    			{
    				int ans = find1(rot << 1, lt, mid, pos);
    				if (ans <= N)
    					return ans;
    			}
    			if (!tree[rot << 1 | 1].all0)
    				return find1(rot << 1 | 1, mid + 1, rt, pos);
    			else
    				return N + 1;
    		}
    		void init()
    		{
    			cov0(1);
    		}
    	}
    	ull extract(const ull a, const int l, const int r)
    	{
    		return (a & ((1ULL << r) - 1ULL)) >> l;
    	}
    	bool check(const ull a, const int p)
    	{
    		return a & (1ULL << p);
    	}
    	void add(const ull a, const int p)
    	{
    		using namespace Segment_Tree;
    		ull now = query(1, 0, N, p);
    		if (now + a >= BASE)
    		{
    			int pos = find0(1, 0, N, p + 1);
    			ull tmp = query(1, 0, N, pos);
    			change(1, 0, N, pos, tmp + 1ULL);
    			if (pos > p + 1)
    				cover0(1, 0, N, p + 1, pos - 1);
    		}
    		change(1, 0, N, p, (now + a) % BASE);
    	}
    	void sub(const ull a, const int p)
    	{
    		using namespace Segment_Tree;
    		ull now = query(1, 0, N, p);
    		if (now < a)
    		{
    			int pos = find1(1, 0, N, p + 1);
    			ull tmp = query(1, 0, N, pos);
    			change(1, 0, N, pos, tmp - 1ULL);
    			if (pos > p + 1)
    				cover1(1, 0, N, p + 1, pos - 1);
    		}
    		change(1, 0, N, p, (now - a + BASE) % BASE);
    	}
    	int work()
    	{
    		using namespace Segment_Tree;
    		int n, t1, t2, t3;
    		read(n), read(t1), read(t2), read(t3);
    		init();
    		while (n--)
    		{
    			int opt;
    			read(opt);
    			if (opt == 1)
    			{
    				int a, b;
    				read(a), read(b);
    				if (a > 0) //ADD
    				{
    					add(extract(a, 0, DIGIT - b % DIGIT) << (b % DIGIT), b / DIGIT);
    					add(extract(a, DIGIT - b % DIGIT, DIGIT), b / DIGIT + 1);
    				}
    				else if (a < 0)
    				{
    					a = -a;
    					sub(extract(a, 0, DIGIT - b % DIGIT) << (b % DIGIT), b / DIGIT);
    					sub(extract(a, DIGIT - b % DIGIT, DIGIT), b / DIGIT + 1);
    				}
    			}
    			else
    			{
    				int k;
    				read(k);
    				write(check(query(1, 0, N, k / DIGIT), k % DIGIT) ? 1 : 0), putchar('
    ');
    			}
    		}
    		return 0;
    	}
    }
    int main()
    {
    #ifdef BlueSpirit
    	freopen("3822.in", "r", stdin);
    	freopen("3822.out", "w", stdout);
    #endif
    	return zyt::work();
    }
    
  • 相关阅读:
    sysbench压测Oracle
    linux使用FIO测试磁盘的iops
    oracle 列授权相关测试
    11G、12C安装结束需要做的一些操作
    Oracle 12C R2 on Linux 7.X 单实例静默安装文档
    auto_create_partition
    关于使用索引的一些经验
    转:【Python3网络爬虫开发实战】 requests基本用法
    转:http协议学习系列(响应头---Response Headers)
    关于建立老猿Python研学群的公告
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/10993308.html
Copyright © 2011-2022 走看看