首页 > 其他分享 >洛谷P7907 [Ynoi2005] rmscne

洛谷P7907 [Ynoi2005] rmscne

时间:2022-09-03 15:12:31浏览次数:62  
标签:rmscne 洛谷 ll pos Ynoi2005 tot 端点 return buf

数据结构好题

首先将询问离线,扫描线扫答案区间的左端点。

设和 \(l\) 颜色相同的下一个位置为 \(x\) 。

那么对于左端点 \(\leq l\),\(l \leq\) 右端点 $<x $ 的询问, \(l\) 再往右移动的话一定是不合法的,找到这些询问并且删除即可。

设所有出现位置全部在 (l,x) 外的颜色中在 \(x\) 后最小的位置为 \(y\)。

对于右端点 \(>=y\) 的询问,他的答案区间如果以 \(l\) 为端点一定不优,因为如果以 \(l\) 为端点他一定会包含 \(y\),也就包含 \(x\),不如往右移,不用考虑。

所以我们只需要维护右端点在 \(x,y\) 之间的区间就可以了,这可以二维数电来维护。

但是这样会出现问题,就是会修改到之间已经删除掉的不合法的区间。

只要在删除的时候把右端点改成答案区间的右端点就好了。

代码

#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
#define eps 1e-10
using namespace std;
typedef int ll;
typedef double db;
const db PI=acos(-1);
const ll mod=64123,inv2=(mod+1)/2,inf=1e9;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
ll n,a[N],m,nxt[N],las[N],ans[N],pd[N],ls[N],rs[N],headv[N],nexv[N],totv,headg[N],nexg[N],totg,totl,nexl[N],v[N],g[N];
inline void vdd(ll x,ll y)
{
	v[++totv]=y;
	nexv[totv]=headv[x];
	headv[x]=totv;
	return;
}
inline void gdd(ll x,ll y)
{
	g[++totg]=y;
	nexg[totg]=headg[x];
	headg[x]=totg;
	return;
}
struct point
{
	ll l,r;
}q[N];
bool vis[N];
struct cc
{
	ll x,l,r,v;
};
struct node
{
	ll val,tag;
}seg[N<<2];
cc lis[N];
inline void build(ll pos,ll l,ll r)
{
	seg[pos].val=seg[pos].tag=inf;
	if(l!=r)
	{
		ll mid=l+r>>1;
		build(pos<<1,l,mid);
		build(pos<<1|1,mid+1,r);
	}
	return;
}
inline void add(ll pos,ll num)
{
	seg[pos].val=seg[pos].val<num?seg[pos].val:num;
	return;
}
ll s,t,num;
inline void upgrade(ll pos,ll l,ll r)
{
	if(l>t||r<s)
		return;
	else if(l>=s&&r<=t)
		return add(pos,num);
	if(num>=seg[pos].val)
		return;
	ll mid=l+r>>1;
	upgrade(pos<<1,l,mid);
	upgrade(pos<<1|1,mid+1,r);
	return;
}
ll res=inf;
inline void query(ll pos,ll l,ll r,ll p)
{
	if(l>p||r<p)
		return;
	res=min(res,seg[pos].val);
	if(l==r)
		return;
	ll mid=l+r>>1;
	if(p<=mid)
		query(pos<<1,l,mid,p);
	else
		query(pos<<1|1,mid+1,r,p);
	return;
}
struct ct
{
	ll siz;
}st[N<<2];
inline ct operator +(ct x,ct y)
{
	return ct{x.siz+y.siz};
}
inline void upd(ll pos,ll l,ll r,ll p,ll num)
{
	ll now=pd[p];
	while(now)
	{
		st[now].siz+=num;
		now>>=1;
	}
	return;
}
struct ncp
{
	ll num;
}sg[N<<2];
inline ncp operator +(ncp x,ncp y)
{
	return ncp{x.num+y.num};
}
inline void update(ll pos,ll l,ll r,ll p)
{
	ll now=pd[p];
	while(now)
	{
		sg[now].num++;
		now>>=1;
	}
	return;
}
inline ll findpre(ll pos,ll l,ll r,ll p)
{
	if(l>p||!st[pos].siz)
		return 0;
	else if(l==r)
		return l;
	ll mid=l+r>>1;
	ll tmp=findpre(pos<<1|1,mid+1,r,p);
	if(tmp)
		return tmp;
	return findpre(pos<<1,l,mid,p);
}
inline ll findnxt(ll pos,ll l,ll r,ll p)
{
	if(r<p||!st[pos].siz)
		return n+1;
	else if(l==r)
		return l;
	ll mid=l+r>>1;
	ll tmp=findnxt(pos<<1,l,mid,p);
	if(tmp!=n+1)
		return tmp;
	return findnxt(pos<<1|1,mid+1,r,p);
}
ll cur;
inline void digui(ll pos,ll l,ll r)
{
	if(!sg[pos].num)
		return;
	else if(l==r)
	{
		ll tmp=findpre(1,1,n,l);
		for(int k=headv[l];k;k=nexv[k])
		{
			int j=v[k];
			ans[j]=ans[j]<tmp-num+1?ans[j]:tmp-num+1;
			q[j].r=tmp;
		}
		headv[l]=0;
		sg[pos].num=0;
		return;
	}
	ll mid=l+r>>1;
	digui(pos<<1|1,mid+1,r);
	digui(pos<<1,l,mid);
	sg[pos]=sg[pos<<1]+sg[pos<<1|1];
	return;
}
inline void work(ll pos,ll l,ll r)
{
	if(!sg[pos].num)
		return;
	if(l>t||r<s)
		return;
	else if(l>=s&&r<=t)
		return digui(pos,l,r);
	ll mid=l+r>>1;
	work(pos<<1|1,mid+1,r);
	work(pos<<1,l,mid);
	sg[pos]=sg[pos<<1]+sg[pos<<1|1];
	return;
}
inline void prework(ll pos,ll l,ll r)
{
	if(l==r)
		pd[l]=pos;
	else
	{
		ll mid=l+r>>1;
		prework(pos<<1,l,mid);
		prework(pos<<1|1,mid+1,r);
	}
	return;
}
static char buf[100000],*pp=buf;
template<class T>inline void pc(T c)
{
    if(pp-buf==100000)fwrite(buf,1,100000,stdout),pp=buf;
    *pp++=c;
}
inline void fsh(){fwrite(buf,1,pp-buf,stdout);pp=buf;}
char cs[N],tot;
inline void write(ll x)
{
	tot=0;
	cs[++tot]='\n';
	while(x)
		cs[++tot]=(x%10)^48,x/=10;
	while(tot)
		pc(cs[tot--]);
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	for(int i=0;i<N;i++)
		las[i]=n+1;
	for(int i=n;i;i--)
	{
		nxt[i]=las[a[i]];
		las[a[i]]=i;
	}
	m=read();
	prework(1,1,n);
	for(int i=1;i<=n;i++)
	{		
		if(vis[a[i]])
			continue;
		vis[a[i]]=true;
		upd(1,1,n,i,1);
	}
	for(int i=1;i<=m;i++)
	{
		ans[i]=inf;
		q[i].l=read();
		q[i].r=read();
		gdd(q[i].l,i);
	}
	for(int i=1;i<=n;i++)
	{
		for(int k=headg[i];k;k=nexg[k])
		{
			int j=g[k];
			vdd(q[j].r,j);
			update(1,1,n,q[j].r);
		}
		s=i,t=nxt[i]-1,num=i;
		work(1,1,n);
		ll tmp=findnxt(1,1,n,nxt[i]);
		lis[++totl]=cc{i,nxt[i],tmp-1,findpre(1,1,n,nxt[i])-i+1};
		if(nxt[i]!=n+1)
			upd(1,1,n,nxt[i],1);
	}
	totv=0;
	for(int i=1;i<=n;i++)
		headv[i]=0;
	for(int i=1;i<=totl;i++)
		vdd(lis[i].x,i);
	build(1,1,n);
	ll cnt=0;
	for(int i=n;i;i--)
	{
		for(int k=headv[i];k;k=nexv[k])
		{
			int j=v[k];
			s=lis[j].l,t=lis[j].r,num=lis[j].v;
			upgrade(1,1,n),cnt++;
		}
		for(int k=headg[i];k;k=nexg[k])
		{
			int j=g[k];
			res=inf;
			query(1,1,n,q[j].r);
			ans[j]=min(ans[j],res);
		}
	}
	for(int i=1;i<=m;i++)
		write(ans[i]);
	fsh();
	quick_exit(0);
}

标签:rmscne,洛谷,ll,pos,Ynoi2005,tot,端点,return,buf
From: https://www.cnblogs.com/CelticBlog/p/16652632.html

相关文章

  • 洛谷深基hash表
    洛谷深基hash表字符串哈希给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串。我们不妨先分......
  • [洛谷P5787] 线段树时间分治
    题目大意给\(n\)个点\(m\)条边,在\(k\)时间内,第\(i\)条边只在\([l_i+1,r_i]\)的时间范围内存在。对于每个\(i\leqk\),输出\(i\)时刻这个图是否是二分图。题......
  • 学习随笔——洛谷题目P1636解答
    摘要:欧拉图的应用。题目原地址如下:https://www.luogu.com.cn/problem/P1636题目截图如下:  一笔画问题,考察欧拉回路的定义,即所有节点的入度出度的和都为偶数即可满足......
  • 洛谷 P6862 [RC-03] 随机树生成器 绿 题解
    前言模数要模\(1e9+9\)!!模数要模\(1e9+9\)!!模数要模\(1e9+9\)!!结论\(n\)个点的树的形态有\((n-1)!\)个,对于节点\(k\),它的所有度数和为\((n-1)!\left(\sum\limits_{......
  • 洛谷 P8496 [NOI2022] 众数 题解
    最近7年最水的D1T1。用权值线段树维护每个数出现的次数,链表维护序列。操作4即合并两棵权值线段树、两个链表,操作2就是删除链表尾的元素并在权值线段树上修改。显......
  • 洛谷-P5058 嗅探器
    嗅探器tarjan割点考虑以\(a\)作为根进行一次\(tarjan\)的搜索,会发现只有到\(b\)的路径上的割点才有可能是最终的答案因此考虑一边标记这个路径,一边在这个路径上......
  • 洛谷 P2582 函数
    函数-洛谷可以发现性质\(g(f^m(x))=f^m(g(x))\)。若设左侧\(x\)所在环大小为\(size(x)\),右侧\(g(x)\)所在环的大小为\(size(gx)\)。可以得到,\(size(gx)\mid......
  • 洛谷-P3388 【模板】割点(割顶)
    【模板】割点(割顶)tarjan学了一下割点,发现就是找\(low[nex]\gedfn[now]\)的点,同时根的话要求有两个分支才能作为割点搜索的时候如果\(nex\)没有被访问过,则直接继续......
  • 洛谷P1001 A+B problem最全算法
    为防止大家说我误导新人,先放一个最不正常的代码。#include<iostream>usingnamespacestd;intmain(){inta,b;cin>>a>>b;cout<<a+b;ret......
  • 洛谷P4619 [SDOI2018]旧试题
    再做一遍,算是复健一下数论。题目链接Description\(T\)组数据,给出\(A,B,C\),求\[\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^Cd(ijk)\]\(d\)表示正因子个数。答案对\(P=1......