首页 > 其他分享 >[Ynoi2016] 镜中的昆虫

[Ynoi2016] 镜中的昆虫

时间:2023-10-17 20:55:16浏览次数:34  
标签:昆虫 qu int Ynoi2016 1048575 tm ls query 镜中

64MB,1.5s

题目描述

您正在欣赏 galgame 的 HS,然后游戏崩溃了,于是您只能做数据结构题了:

维护一个长为 \(n\) 的序列 \(a_i\),有 \(m\) 次操作。

  1. 将区间 \([l,r]\) 的值修改为 \(x\)。

  2. 询问区间 \([l,r]\) 出现了多少种不同的数,也就是说同一个数出现多次只算一个。

输入格式

第一行两个整数 \(n,m\)。

第二行 \(n\) 个整数表示 \(a_i\)。

后面 \(m\) 行每行为 \(1\ l\ r\ x\) 或者 \(2\ l\ r\) ,分别表示修改和询问。

输出格式

对于每个询问,输出一个数表示答案。

样例 #1

样例输入 #1

5 5
1 2 3 4 5
2 1 5
1 2 3 4
2 1 5
2 3 3
2 2 4

样例输出 #1

5
3
1
1

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

数颜色不带修的时候,维护每一种颜色上一次的出现地方 \(ls_i\),对着 \(r\) 扫描线,当 新扫到一个 \(a_i\) 时把树状数组中 \(ls_{a_i}\) 那个地方改掉,把 \(i\) 赋值为 1,询问时后缀查询。

还有一种理解方式:如果一个数 \(i\) 上一次出现在 \(ls\),那么数的时候也就是数有多少个满足 \(l\le i\le r,ls<i\) 的点对。

那么回到原题,只有区间覆盖,可以考虑用 ODT ,然后现在是某一个区间 \([l,r]\) 都是 \(c\),如果 \(c\) 的上一次出现在 ls,那么可以插一个在 \(( ls,l)\) 的价值为 1 的点,插一个在 \((r+1,r)\) 的价值为 -1 的店。

但是可能会把某一个点对删除,所以要增加时间维,在删去时插一个在这个时间把这个点删去的点。

那么在 \(t\) 时刻的询问 \(l,r\) 就是把时间维不超过 \(t\),第一位不超过 \(l\),第二维不超过 \(r\) 的店的价值之和就是颜色数,可以用 CDQ 统计。

然后发现你超时了?把 CDQ 的排序改成归并。

然后发现你 MLE 了? l,r,t 都不超过 1e6,可以压成一个 long long.

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
bool fir;
int n,m,c,ans[N],k,tr[N];
struct node{
	int l,r,w;
	bool operator<(const node&n)const{
		return l<n.l;
	}
};
struct hjhakioi{
	long long k;
	bool operator<(const hjhakioi&q)const{
		if((k>>20&1048575)^(q.k>>20&1048575))
			return (k>>20&1048575)<(q.k>>20&1048575);
		return (k>>60)-1&&(q.k>>60)==1;
	}
}qu[N*19];
set<node>s;
set<pair<int,int> >t[N<<1];
map<int,int>mp;
bool sec;
void upd(int x,int y)
{
	for(;x<=n;x+=x&-x)
		tr[x]+=y;
}
int ask(int x)
{
	int ret=0;
	for(;x;x-=x&-x)
		ret+=tr[x];
	return ret;
}
void query(int x,int y,int t,int op)
{
	qu[++k]=(hjhakioi){(1LL*x<<40LL)^(1LL*y<<20LL)^t^(op+1LL<<60)};
}
void add(int l,int r,int tm,int c)
{
	set<pair<int,int> >::iterator it=t[c].lower_bound(make_pair(l,r));
	if(it!=t[c].end())
	{
		int ls=1;
		if(it!=t[c].begin())
		{
			--it;
			ls=it->second+1;
			++it;
		}
		query(ls,it->first,tm,-1);
		query(r+1,it->first,tm,1);
	}
	int ls=1;
	if(it!=t[c].begin())
	{
		--it;
		ls=it->second+1;
	}
	query(ls,l,tm,1);
	query(r+1,r,tm,-1);
	t[c].insert(make_pair(l,r));
	s.insert((node){l,r,c});
}
void del(int l,int r,int tm,int c)
{
	set<pair<int,int> >::iterator it=t[c].upper_bound(make_pair(l,r)),i;
	if(it!=t[c].end())
	{
		int ls=1;
		i=it;
		query(r+1,it->first,tm,-1);
		--it;
		if(it!=t[c].begin())
		{
			--it;
			ls=it->second+1;
			++it;
		}
		++it;
		query(ls,it->first,tm,1);
	}
	--it;
	int ls=1;
	if(it!=t[c].begin())
	{
		--it;
		ls=it->second+1;
		++it;
	}
	query(ls,l,tm,-1);
	query(r+1,r,tm,1);
	t[c].erase(make_pair(l,r));
	s.erase((node){l,r,c});
}
set<node>::iterator split(int x,int t)
{
	set<node>::iterator it=s.lower_bound((node){x,0,0});
	if(it!=s.end()&&it->l==x)
		return it;
	--it;
	int l=it->l,r=it->r,w=it->w;
	del(l,r,t,w);
	add(l,x-1,t,w);
	add(x,r,t,w);
	return s.lower_bound((node){x,r,w});
}
void solve(int l,int r,int x,int y)
{
	if(x>y)
		return;
	if(l^r)
	{
		int md=l+r>>1,k=y+1;
		for(int i=x;i<=y;i++)
			if((qu[i].k&1048575)>md)
				k=i,i=y;
		solve(l,md,x,k-1);
		solve(md+1,r,k,y);
		inplace_merge(qu+x,qu+k,qu+y+1);
	}
	sort(qu+x,qu+y+1);
	int md=l+r>>1;
	for(int i=x;i<=y;i++)
	{
		if(1==(qu[i].k>>60)&&(qu[i].k&1048575)>md)
			ans[qu[i].k&1048575]+=ask(qu[i].k>>40&1048575);
		if(1^(qu[i].k>>60)&&(qu[i].k&1048575)<=md)
			upd(qu[i].k>>40&1048575,(qu[i].k>>60)-1);
	}
	for(int i=x;i<=y;i++)
		if(1^(qu[i].k>>60)&&(qu[i].k&1048575)<=md)
			upd(qu[i].k>>40&1048575,1-(qu[i].k>>60));
}
void write(int x)
{
	if(!x)
		return;
	write(x/10);
	putchar(x%10+48);
}
int read()
{
	int s=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')
		ch=getchar();
	while(ch>='0'&&ch<='9')
		s=s*10+ch-48,ch=getchar();
	return s;
}
int main()
{
	memset(ans,-1,sizeof(ans));
	scanf("%d%d",&n,&m);
	for(int i=1,x;i<=n;i++)
	{
		if(!mp[x=read()])
			mp[x]=++c;
		add(i,i,0,mp[x]);
	}
	for(int i=1,op,l,r,x;i<=m;i++)
	{
		op=read(),l=read(),r=read();
		if(op^2)
		{
			if(!mp[x=read()])
				mp[x]=++c;
			set<node>::iterator itr=split(r+1,i),itl=split(l,i);
			for(set<node>::iterator it=itl,j;it!=itr;)
			{
				j=it;
				it++;
				del(j->l,j->r,i,j->w);
			}
			add(l,r,i,mp[x]);
		}
		else
			query(l,r,i,ans[i]=0);
	}
	solve(0,m,1,k);
	for(int i=1;i<=m;i++)
		if(~ans[i])
			write(ans[i]),puts("");
}

标签:昆虫,qu,int,Ynoi2016,1048575,tm,ls,query,镜中
From: https://www.cnblogs.com/mekoszc/p/17770642.html

相关文章

  • [Ynoi2016] 这是我自己的发明(根号分治+分块/莫队)
    题目传送门soltion简单题换根显然可以拆成\(O(1)\)个区间,这里先不管。直接做法是莫队,把双子树拆成\(dfs\)序上的双前缀,可以直接莫队,但是常数比较大。另一种做法是根分,对颜色出现次数分治,大于的求出\(dfs\)序的前缀和即可,小于的因为一共只有\(O(n\sqrtn)\)个点对,所以......
  • 1312:【例3.4】昆虫繁殖
    1312:【例3.4】昆虫繁殖时间限制:1000ms      内存限制:65536KB提交数:41168   通过数:20495【题目描述】科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强。每对成虫过x�个月产y�对卵,每对卵要过两个月长成成虫。假设每个成虫不死,第一个月只......
  • 昆虫繁殖
    #include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intx,y,z;inta(intz){if(z<x+2){return1;}returna(z-1)+a(z-x-2)*y;//a(n-1)*n}intmain(){intc;cin>>x>>y>&......
  • 昆虫繁殖
    #include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intx,y,z;inta(intz){if(z<x+2){return1;}returna(z-1)+a(z-x-2)*y;//a(n-1)*n}intmain(){intc;cin>>x>>y>&......
  • 昆虫学家教你灭蟑螂
    昆虫学家教你灭蟑螂硼酸一小袋白色粉末,两个土豆,两勺白糖,两勺硼酸,土豆蒸熟弄成土豆泥,全部弄一起,搅拌后搓成丸子。放在蟑螂出没位置,放点水,防止干了,蟑螂吃了之后会非常渴,去下水道的位置,基本都死那块了。硼酸曾被美国国家环境保护局当作控制蟑螂、白蚁、火蚁、跳蚤、蠹鱼和其他害......
  • luogu P4690 [Ynoi2016] 镜中的昆虫 题解
    P4690[Ynoi2016]镜中的昆虫题解题意维护一个长为 \(n\) 的序列 \(a_i\),有 \(m\) 次操作。将区间 \([l,r]\) 的值修改为 \(x\)。询问区间 \([l,r]\) 出现了多少种不同的数,也就是说同一个数出现多次只算一个。题解感觉这道题还是比较有意思的,像是一堆套路......
  • 镜中
    镜中只要想起一生中后悔的事梅花便落了下来比如看她游泳到河的另一岸比如登上一株松木梯子危险的事固然美丽不如看她骑马归来面颊温暖,羞惭。低下头,回答着皇帝一面镜子永远等候她让她坐到镜中常坐的地方望着窗外,只要想起一生中后悔的事梅花便落满了南山这是我最喜欢的......
  • P4688 [Ynoi2016] 掉进兔子洞
    RE了大约12次以后,SoN3ri告诉我是bitset开小了。那你为什么全RE了啊(?题意是给你一个长度为\(n\)的序列,一共\(m\)次询问,每次询问包含三个区间,求三个区间内相同的数去掉后剩下的数的个数。做完了小清新人渣的本愿,看啥都是bitset+莫队,这题我也是一开始打了一个莫队+bitset,但是......
  • [IOI2022] 最罕见的昆虫
    [IOI2022]最罕见的昆虫题目描述PakBlangkon的房子四周有\(N\)只昆虫,编号为\(0\)至\(N-1\)。每只昆虫有一个类型,以从\(0\)至\(10^9\)(包含\(0\)和\(10^9\))的......
  • [Ynoi2016] 掉进兔子洞
    \(\text{Solution}\)莫队配合\(\text{bitset}\)发现答案困难的部分在于同一个数在三个区间出现次数的最小值考虑强行拆开看,用莫队处理出每个区间每个数的出现次数,这个......