洛谷P7907 [Ynoi2005] rmscne

数据结构好题

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

设和 l 颜色相同的下一个位置为 x

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

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

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

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

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

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

代码

Copy
#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); }
posted @   CelticOIer  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2020-09-03 题解 [NOI2014]魔法森林
点击右上角即可分享
微信分享提示