首页 > 其他分享 >【Ynoi 2016】掉进兔子洞

【Ynoi 2016】掉进兔子洞

时间:2024-09-02 21:47:51浏览次数:3  
标签:arr int pos 兔子 Ynoi bitset cnt idxr 2016

Luogu P4688 掉进兔子洞

题意

给定一个长度为 \(n\) 的序列 \(a\)。

有 \(m\) 次询问:每次询问给定三个区间,问将三个区间内同时出现的数删掉后,还剩下多少个数。每次询问独立。

数据范围与约定

\(1 \le n,m \le 10^5\),\(1 \le a_i \le 10^9\)。

题解

首先发现,每次询问的答案形式为:\(ans_i=len_1+len_2+len_3-3*size\),其中 \(size\) 为三个区间内同时出现的颜色的个数。

所以只要我们有办法求出 \(size\) 就能解决这道题。很自然的想到 bitset 维护区间内出现的颜色,求一下交集。但是我们要求的是同时出现的颜色个数,而不是颜色种数。bitset 只能记录一个颜色存在或者不存在,不能记录存在多少个。如果换成数组,又没有了除 \(w\) 的常数。

我们可以在离散化上下手,令一个颜色离散化后的值为:序列中,小于这个数的个数加 \(1\)(不加 \(1\) 也行,随便你)。其实就是离散化把去重给去掉而已。

这样有一个好处,我们假设当前颜色为 \(c_1\),下一个颜色为 \(c_2\)。那么 \(c_2-c_1\) 就是 \(c_1\) 的个数。所以如果颜色 \(c_1\) 出现了 \(cnt\) 次。我们可以在 bitset 上令 \(c_1+cnt-1\) 为 \(1\)。这里需要注意一下,我们不应该把 \(c_1+(cnt-1)-1\) 再置为 \(0\),而是将其保留。这样有一个好处,\(c_1\) 和 \(c_2\) 之间 \(1\) 的个数,就是 \(c_1\) 出现的次数。那么最后三个区间交集的 bitset 的 \(1\) 的个数,就是我们要求的 \(size\)。

最后一个问题,怎么求每个区间的 bitset?考虑到这个 bitset 因为我们离散化比较特殊的原因,没办法通过区间合并来快速得到,所以不能使用分块或者线段树之类的数据结构了。所以我们考虑使用莫队。

这里有一个问题,我们开不下 \(1e5\) 个长度为 \(1e5\) 的 bitset。我们可以对问题分组,每 \(4e4\) 个问题跑一次莫队,这样我们只需要跑 \(\left\lceil \frac{1e5}{4e4} \right\rceil=3\) 次莫队即可。

代码

#include<bits/stdc++.h>
using namespace std;
/*====================*/
#define endl "\n"
/*====================*/
typedef long long lnt;
/*====================*/
const int N = 1e5 + 10;
const int M = 1e5 + 10;
const int S1 = 4e4;//对询问分组
const int S2 = 350;//对莫队分组
/*====================*/
int n, m;
int arr[N];
/*====================*/
struct Query
{
	int l, r, idx;
	Query(int _l = 0, int _r = 0, int _idx = 0)
	{
		l = _l, r = _r, idx = _idx;
	}
	friend bool operator<(const Query& a, const Query& b)
	{
		return (a.l / S2 == b.l / S2) ? (((a.l / S2) & 1) ? (a.r > b.r) : (a.r < b.r)) : (a.l < b.l);
	}
}query[3 * M];
/*====================*/
int ans[M];
/*====================*/
int cnt[N];
bitset<N>temp;
bitset<N>state[S1];
void Add(int pos)
{
	temp[arr[pos] + ++cnt[arr[pos]] - 1] = 1;
}
void Del(int pos)
{
	temp[arr[pos] + cnt[arr[pos]]-- - 1] = 0;
}
void Mo(int idxl, int idxr)
{
	int askl = (idxl - 1) * 3 + 1;
	int askr = (idxr - 1) * 3 + 3;
	sort(query + askl, query + askr + 1);
	/*====================*/
	temp.reset();
	for (int i = idxl; i <= idxr; ++i)
	{
		state[i % S1].set();
	}
	memset(cnt, 0, sizeof(cnt));
	/*====================*/
	int l = 1, r = 0;
	for (int i = askl; i <= askr; ++i)
	{
		while (query[i].l < l)Add(--l);
		while (r < query[i].r)Add(++r);
		while (l < query[i].l)Del(l++);
		while (query[i].r < r)Del(r--);
		state[query[i].idx % S1] &= temp;
	}
	/*====================*/
	for (int i = idxl; i <= idxr; ++i)
	{
		ans[i] -= 3 * state[i % S1].count();
	}
}
/*====================*/
void Solve(void)
{
	do
	{
		cin >> n >> m;
		for (int i = 1; i <= n; ++i)
		{
			cin >> arr[i];
		}
	} while (false);//读入

	do
	{
		vector<int>lib;
		for (int i = 1; i <= n; ++i)
		{
			lib.push_back(arr[i]);
		}
		sort(lib.begin(), lib.end());
		for (int i = 1; i <= n; ++i)
		{
			arr[i] = lower_bound(lib.begin(), lib.end(), arr[i]) - lib.begin() + 1;
		}
	} while (false);//离散化

	do
	{
		int idxl = 1, idxr = S1; idxr = min(idxr, m);
		while (idxl <= idxr)
		{
			for (int i = idxl; i <= idxr; ++i)
			{
				for (int j = 1; j <= 3; ++j)
				{
					int l, r; cin >> l >> r;
					query[(i - 1) * 3 + j] = Query(l, r, i);
					ans[i] += r - l + 1;
				}
			}
			Mo(idxl, idxr);
			idxl += S1, idxr += S1; idxr = min(idxr, m);
		}

	} while (false);//莫队

	do
	{
		for (int i = 1; i <= m; ++i)
		{
			cout << ans[i] << endl;
		}
	} while (false);//输出
}
/*====================*/
int main()
{
#ifndef ONLINE_JUDGE
	freopen("IN.txt", "r+", stdin);
#endif
	ios::sync_with_stdio(false);
	cin.tie(NULL), cout.tie(NULL);
	int T = 1; //cin >> T;
	while (T--)Solve();
	return 0;
}

标签:arr,int,pos,兔子,Ynoi,bitset,cnt,idxr,2016
From: https://www.cnblogs.com/ProtectEMmm/p/18393616

相关文章

  • [蓝桥杯 2016 省 A] 密码脱落--最长公共子序列题解
    题目复述:题目链接:[蓝桥杯2016省A]密码脱落-洛谷#[蓝桥杯2016省A]密码脱落##题目描述X星球的考古学家发现了一批古代留下来的密码。这些密码是由A、B、C、D四种植物的种子串成的序列。仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的回文串)。......
  • Windows Server 2016 OVF, updated Aug 2024 (sysin) - VMware 虚拟机模板
    WindowsServer2016OVF,updatedAug2024(sysin)-VMware虚拟机模板2024年8月版本更新,现在自动运行sysprep,支持ESXiHostClient部署请访问原文链接:https://sysin.org/blog/windows-server-2016-ovf/,查看最新版。原创作品,转载请保留出处。现在都是自动sysprep的......
  • Windows Server 2016 中文版、英文版下载 (updated Aug 2024)
    WindowsServer2016中文版、英文版下载(updatedAug2024)WindowsServer2016Version1607请访问原文链接:https://sysin.org/blog/windows-server-2016/,查看最新版。原创作品,转载请保留出处。本站将不定期发布官方原版风格月度更新ISO。WindowsServer2016直接上链......
  • P2825 [HEOI2016/TJOI2016] 游戏 与 P10945 Place the Robots
    本文中的机器人同炸弹,主要是题目描述不同,两道题目做法是本质相同的。思路:先说一下没有墙怎么办,那么当一个位置放了机器人之后,这个机器人所在的行和列是不能继续放置的。那么发现行和列几乎是独立的,考虑建二分图,若\((i,j)\)能放一个机器人,那么给\(i\toj\)建一条边。那么......
  • Ynoi 做题笔记(2024 年暑假)
    P9992[YnoiEasyRound2024]TEST_130之前大概想出来了,但是没想清楚。发现每次询问\(w,d\)就相当于算\(w\)子树里离\(w\)距离不超过\(d\)的点的贡献之和,\(w\)的贡献是\(d+1\)(因为\(N(w,0),N(w,1),\ldots,N(w,d)\)都可以),\(w\)往下第一层的每个点分别的贡......
  • 历年CSP-J初赛真题解析 | 2016年CSP-J初赛阅读程序(23-26)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客#include<iostream>usingnamespacestd;intmain(){intmax,min,sum,count=0;inttmp;cin>>tmp;......
  • P4069 [SDOI2016] 游戏
    思路首先,我们可以将一条要标记的路线\((s,t)\)分成\((s,lca)\)和\((lca,t)\)两个部分,这两个部分分别对应一种\(y=kx+b\)。代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;usingi64=longlong;constintN=100010;consti64......
  • 大白话【8】WindowsServer2016搭建DNS服务
    1.DNS服务功能介绍2.DNS服务器搭建2.0准备环境2.1把该DNS服务器设置成静态IP2.2修改主机名(可省略)2.3安装DNS服务DNS服务器名为www;IP为192.168.2.1003.客户机测试在网内可网络连通的客户机如何验证DNS服务器域名解析有效性?3.1可以ping不通,只要看到解析就行。......
  • 大白话【7】windows server2016共享目录配置
    1.windows权限模型案列共享目录搭建过程1.创建共享目录2.为人力资源部,销售部,IT部,等创建工作组3.创建用户关联用户组4.修改共享目录权限,允许xx工作组用户进入目录5.根据需求设置XX目录权限6.开启目录共享打开本地用户和组Win+R 输入lusrmgr.msc引申-普通用户想要使......
  • 信息学奥赛初赛天天练-75-NOIP2016普及组-完善程序-二分答案、二分查找、贪心算法、贪
    1完善程序(单选题,每小题3分,共30分)郊游活动有n名同学参加学校组织的郊游活动,已知学校给这n名同学的郊游总经费为A元,与此同时第i位同学自己携带了Mi元。为了方便郊游,活动地点提供B(≥n)辆自行车供人租用,租用第j辆自行车的价格为Cj元,每位同学可以使用自己携带的钱或......