莫队去离线询问暴力`
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int ans[N];
int a[N];
int bl[N];
int n,m;
int now;
int c[N];
struct node
{
int l;
int r;
int id;
bool operator <(const node&a)const
{
return bl[l]^bl[a.l]?bl[l]<bl[a.l]:bl[l]&1?r<a.r:r>a.r;
}
}q[N];
void add(int x)
{
c[a[x]]++;
while(c[now])++now;
}
void del(int x)
{
if(!c[a[x]])now=min(now,a[x]);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
int len=sqrt(len);
for(int i=1;i<=n;i++)
{
bl[i]=(i-1)/len+1;
}
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
q[i]={x,y,i};
}
sort(q+1,q+m+1);
for(int i=1,l=1,r=0;i<=m;i++)
{
int x=q[i].l;
int y=q[i].r;
int id=q[i].id;
while(r<y)add(++r);
while(r>y)del(r--);
while(l<x)del(l++);
while(l>x)add(--r);
ans[id]=now;
}
for(int i=1;i<=m;i++)
{
cout<<ans[i]<<endl;
}
return 0;
}
主席树
思路
我们每次建立一颗[1, i]的权值线段树 维护出他们出现的最右边位置
当每次询问的时候 我们查询 第y颗线段树 找到小于l的第一个位置即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e6+10;
int a[N*33];
int lc[N*33],rc[N*33];
int r[N],last[N];
int v[N];
int id;
int n,m;
void change(int l,int r,int &rt,int last,int val,int x)
{
rt=id++;
lc[rt]=lc[last],
rc[rt]=rc[last];
if(l==r)
{
v[rt]=x;
return ;
}
int mid=l+r>>1;
if(val<=mid) change(l,mid,lc[rt],lc[last],val,x);
else change(mid+1,r,rc[rt],rc[last],val,x);
v[rt]=min(v[lc[rt]],v[rc[rt]]);
}
int query (int l,int r,int rt,int k)
{
if(l==r)return r;
int mid=l+r>>1;
if(v[lc[rt]]>=k)return query(mid+1,r,rc[rt],k);
else query(l,mid,lc[rt],k);
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i],change(0,1e9,r[i],r[i-1],a[i],i);
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
cout<<query(0,1e9,r[y],x)<<endl;
}
return 0;
}
用结构体的写法 //主席树空间开销比较大
struct node
{
int l;
int r;
int v;
}t[N*40];
void build(int &now,int last,int l,int r,int val,int x)
{
now=id++;
t[now]=t[last];
if(l==r)
{
t[now].v=x;
return ;
}
int mid=(l+r)>>1;
if(val<=mid)
build(t[now].l,t[last].l,l,mid,val,x);
else
build(t[now].r,t[last].r,mid+1,r,val,x);
t[now].val=min(t[t[now].l].v,t[t[now].r].v);
}
int query(int now,int l,int r,int k)
{
if(l==r)return r;
int mid=l+r>>1;
if(t[t[now].l]>=k)return query(mid+1,r,t[now].r,k);
else return query(l,mid,t[now].l,k);
}
线段树
带补....