• 【BZOJ4241】历史研究(回滚莫队)


    题目:

    BZOJ4241

    分析:

    本校某些julao乱膜的时候发明了个“回滚邹队”,大概意思就是某个姓邹的太菜了进不了省队回滚去文化课

    回滚莫队裸题qwq(话说这个名字是不是莫队本人起的啊这么萌zui

    首先看到题询问区间信息+没强制在线,妥妥的莫队。然而朴素的莫队(开个桶记每种事件当前的重要度,用set或者堆之类维护一下答案)要(O(nsqrt n log n)),直接T了……

    兔崽子给我说有一种神奇的分块做法,然而我太菜了还没写,先挖个坑以后再补。

    然后我去网上orz题解,看到一种叫“回滚莫队”的神奇的东西。可以发现,朴素莫队的问题在于区间变长的时候可以(O(1))更新答案,但是为了维护区间变短必须要套个(log n)的数据结构。所以,如果不存在区间变短的情况,就可以直接(O(1))更新答案,总复杂度(O(nsqrt n))了。

    考虑左端点在同一块中的所有询问,它们的右端点是单调非降的。对于左右端点在同一块中的询问,直接暴力查询即可。否则,设左端点所在块的下一块开头为(pos),用一个指针(r)往右扫,统计([pos,r])的答案。此时还有([l,pos))的答案没有统计。对于每个询问,暴力(O(sqrt n))统计这部分答案,最后对两部分答案取(max)即可。具体参见代码。

    代码:

    朴素莫队(TLE):

    (一开始离散化写炸了WA了几发……菜死了)

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    #define _ 0
    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)
    	{
    		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 long long ll;
    	const int N = 1e5 + 10, Q = 1e5 + 10;
    	int n, q, block, belong[N], arr[N], tmp[N];
    	ll ans[N];
    	struct _ask
    	{
    		int l, r, id;
    		bool operator < (const _ask &b) const
    		{
    			return belong[l] == belong[b.l] ? r < b.r : belong[l] < belong[b.l];
    		}
    	}ask[Q];
    	namespace Mo_Algorithm
    	{
    		priority_queue<ll> pq, del;
    		ll num[N];
    		void update(const int pos, const int x)
    		{
    			del.push(num[pos]);
    			num[pos] += (ll)tmp[pos] * x;
    			pq.push(num[pos]);
    			while (!del.empty() && pq.top() == del.top())
    				pq.pop(), del.pop();
    		}
    		void solve(const int maxx)
    		{
    			int l = 1, r = 1;
    			for (int i = 1; i <= maxx; i++)
    				pq.push(0);
    			update(arr[1], 1);
    			for (int i = 1; i <= q; i++)
    			{
    				while (l < ask[i].l)
    					update(arr[l++], -1);
    				while (l > ask[i].l)
    					update(arr[--l], 1);
    				while (r < ask[i].r)
    					update(arr[++r], 1);
    				while (r > ask[i].r)
    					update(arr[r--], -1);
    				ans[ask[i].id] = pq.top();
    			}
    		}
    	}
    	int work()
    	{
    		read(n), read(q);
    		block = pow(n, 0.5);
    		for (int i = 1; i <= n; i++)
    		{
    			read(arr[i]), tmp[i] = arr[i];
    			belong[i] = (i - 1) / block + 1;
    		}
    		sort(tmp + 1, tmp + n + 1);
    		int cnt = unique(tmp + 1, tmp + n + 1) - tmp;
    		for (int i = 1; i <= n; i++)
    			arr[i] = lower_bound(tmp + 1, tmp + cnt, arr[i]) - tmp;
    		for (int i = 1; i <= q; i++)
    		{
    			read(ask[i].l), read(ask[i].r);
    			ask[i].id = i;
    		}
    		sort(ask + 1, ask + q + 1);
    		Mo_Algorithm::solve(cnt);
    		for (int i = 1; i <= q; i++)
    			write(ans[i]), putchar('
    ');
    		return (0^_^0);
    	}
    }
    int main()
    {
    	return zyt::work();	
    }
    

    回滚莫队(AC):

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    #define _ 0
    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)
    	{
    		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 long long ll;
    	const int N = 1e5 + 10, Q = 1e5 + 10;
    	int n, q, block, belong[N], arr[N], tmp[N];
    	ll ans[N];
    	struct _ask
    	{
    		int l, r, id;
    		bool operator < (const _ask &b) const
    		{
    			return belong[l] == belong[b.l] ? r < b.r : belong[l] < belong[b.l];
    		}
    	}ask[Q];
    	inline int begin(const int a)
    	{
    		return (a - 1) * block + 1;
    	}
    	namespace Mo_Algorithm
    	{
    		ll solve_small(const int l, const int r)
    		{
    			static ll num[N];
    			ll ans = 0;
    			for (int i = l; i <= r; i++)
    				ans = max(ans, num[arr[i]] += tmp[arr[i]]);
    			for (int i = l; i <= r; i++)
    				num[arr[i]] = 0;
    			return ans;
    		}
    		void solve(const int maxx)
    		{
    			static ll num[N];
    			ll now = 0;
    			int l, r, lbegin;
    			for (int i = 1; i <= q; i++)
    			{
    				if (belong[ask[i].l] != belong[ask[i - 1].l])
    				{
    					memset(num, 0, sizeof(ll[maxx + 1]));
    					lbegin = begin(belong[ask[i].l] + 1), l = lbegin, r = lbegin - 1;
    					now = 0;
    				}
    				if (belong[ask[i].l] == belong[ask[i].r])
    					ans[ask[i].id] = solve_small(ask[i].l, ask[i].r);
    				else
    				{
    					while (r < ask[i].r)
    					{
    						++r;
    						now = max(now, num[arr[r]] += tmp[arr[r]]);
    					}
    					ll bck = now;
    					while (l > ask[i].l)
    					{
    						--l;
    						now = max(now, num[arr[l]] += tmp[arr[l]]);
    					}
    					ans[ask[i].id] = now;
    					while (l < lbegin)
    					{
    						num[arr[l]] -= tmp[arr[l]];
    						++l;
    					}
    					now = bck;
    				}
    			}
    		}
    	}
    	int work()
    	{
    		read(n), read(q);
    		block = pow(n, 0.5);
    		for (int i = 1; i <= n; i++)
    		{
    			read(arr[i]), tmp[i] = arr[i];
    			belong[i] = (i - 1) / block + 1;
    		}
    		sort(tmp + 1, tmp + n + 1);
    		int cnt = unique(tmp + 1, tmp + n + 1) - tmp;
    		for (int i = 1; i <= n; i++)
    			arr[i] = lower_bound(tmp + 1, tmp + cnt, arr[i]) - tmp;
    		for (int i = 1; i <= q; i++)
    		{
    			read(ask[i].l), read(ask[i].r);
    			ask[i].id = i;
    		}
    		sort(ask + 1, ask + q + 1);
    		Mo_Algorithm::solve(cnt);
    		for (int i = 1; i <= q; i++)
    			write(ans[i]), putchar('
    ');
    		return (0^_^0);
    	}
    }
    int main()
    {
    	return zyt::work();	
    }
    
  • 相关阅读:
    PHP_Code_challenge(代码审计)
    超全局变量$GLOBALS
    upload-labs(文件上传)
    CTF bugku 论剑场 web20
    多次Printf()是否使用用同一栈帧的参数?
    (转载于度盘)小迪安全渗透-学习讲义
    SQL数据库操作练习(2)
    .htaccess绕过
    PHP序列化思考(9.14已修改)
    SQL数据库操作练习(1)
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/10159279.html
Copyright © 2020-2023  润新知