【题意】
有一个长度为
n
的数组
【数据范围】
n,q≤200000
0≤ai≤200000
且
ai∈Z
0<l≤r≤n
【分析1】30%做法:暴力
空间复杂度:
O(n2)
时间复杂度:
O(n2)
【分析2】树套树?
解决多个询问,考虑在线算法和离线算法。
先是在线算法,首先http://tieba.baidu.com/p/2813942502的算法应该错。
然后树套树应该是可以的。
但是蒟蒻并不会,所以以后应该会补充……
时间复杂度:
O(nlog2n)
空间复杂度:
unknown
【分析3】60%做法:莫队算法+线段树/树状数组
考虑离线算法。区间的离线算法,想到了莫队。
用
v[i]
表示区间
[l,r]
中存在
v[i]
的个数,然后如果
v[i]>0
,则
v[i
]的权值赋为
1
。
莫队移动的过程中,维护
查找方法是从高位枚举到低位,检查权值是否满了,如果满了就用
inc(cnt,2i)
。
时间复杂度:
O(nn√logn)
空间复杂度:
O(n)
代码:
(PS:时限是
1s
,然而我剩下
4
个点最多只有
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=262144;//131072*2
const int MAX_BIT=20;
int n,m;
int a[N];
int unit;
struct Ques
{
int l,r,id;
friend inline int operator < (Ques qa,Ques qb)
{
return qa.l/unit!=qb.l/unit?qa.l/unit<qb.l/unit:qa.r<qb.r;
}
}q[N];
int ans[N];
int v[N];
struct TreeArray
{
int t[N];
inline int lowbit(int i)
{
return i&-i;
}
inline void ins(int i,int add)
{
for (;i<N;i+=lowbit(i)) t[i]+=add;
}
inline int query(void)
{
int now=0;
for (int i=MAX_BIT;i>=0;i--)
if (now+(1<<i)<N&&t[now+(1<<i)]==1<<i) now+=1<<i;
return now;
}
}tr;
inline int Read(void)
{
int x=0; char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
int main(void)
{
n=Read(),m=Read();
for (int i=1;i<=n;i++) a[i]=Read();
for (int i=1;i<=m;i++) q[i].l=Read(),q[i].r=Read(),q[i].id=i;
unit=(int)sqrt(n);
sort(q+1,q+m+1);
int l=1,r=0;
for (int i=1;i<=m;i++)
{
for (;l<q[i].l;l++)
{
v[a[l]]--;
if (!v[a[l]]) tr.ins(a[l]+1,-1);
}
for (;l>q[i].l;l--)
{
v[a[l-1]]++;
if (v[a[l-1]]==1) tr.ins(a[l-1]+1,1);
}
for (;r<q[i].r;r++)
{
v[a[r+1]]++;
if (v[a[r+1]]==1) tr.ins(a[r+1]+1,1);
}
for (;r>q[i].r;r--)
{
v[a[r]]--;
if (!v[a[r]]) tr.ins(a[r]+1,-1);
}
ans[q[i].id]=tr.query();
}
for (int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
【分析4】100%做法:固定左端点,线段树维护每个点的 sg 值
几个参考:
http://hzwer.com/3032.html
http://tieba.baidu.com/p/2813942502
这里只提实现线段树的方法有两种:①标久化标记 ②标记下传
方法①会快一些,在查询单点时只用取根到当前点路径的最小值。
时间复杂度:
O(nlogn)
空间复杂度:
O(nlogn)
代码:
/**************************************************************
Problem: 1286
User: YPL
Language: C++
Result: Accepted
Time:236 ms
Memory:54224 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=200010;
const int Q=200010;
const int A=200010;
const int S=4000000;
int n,m;
int a[N];
struct Ques
{
int l,r,id;
friend inline int operator < (Ques qa,Ques qb)
{
return qa.l<qb.l;
}
}q[Q];
int ans[Q];
inline int read(void)
{
int x=0,f=1; char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
int v[A];
int nxt[N];
int firSG[N],now;
void Init(void)
{
n=read(),m=read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1);
fill(v,v+n+1,n+1);
for (int i=n;i>=1;i--) nxt[i]=v[a[i]],v[a[i]]=i;
memset(v,0,sizeof v);
for (int i=1;i<=n;i++) { for (v[a[i]]=1;v[now];now++); firSG[i]=now; }
}
struct SegmentTree
{
struct TreeNode
{
int l,r;
int mex;
}tr[S];
void build(int now,int l,int r)
{
tr[now].l=l;
tr[now].r=r;
tr[now].mex=A;
if (l!=r)
{
int mid=l+r>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
}
else tr[now].mex=firSG[l];
}
void ins(int now,int l,int r,int w)
{
if (l<=tr[now].l&&tr[now].r<=r) {tr[now].mex=min(tr[now].mex,w);return;}
int mid=tr[now].l+tr[now].r>>1;
if (l<=mid) ins(now<<1,l,r,w);
if (mid<r) ins(now<<1|1,l,r,w);
}
int query(int now,int loc)
{
if (tr[now].l==tr[now].r) return tr[now].mex;
return min(tr[now].mex,query(now<<1|loc>tr[now].l+tr[now].r>>1,loc));
}
}tr;
int cir=1;
void Work(void)
{
tr.build(1,1,n);
for (int i=1;i<=m;i++)
{
for (;cir<q[i].l;cir++)
tr.ins(1,cir+1,nxt[cir]-1,a[cir]);
ans[q[i].id]=tr.query(1,q[i].r);
}
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
int main(void)
{
Init();
Work();
return 0;
}
【小结】
多个询问的处理维度:在线算法,离线算法
区间 [l,r] 离线处理的常见排序方法:
①按照 l 排序
②按照r 排序
③分块排序
通常①②的方法效率会比③高。区间答案的处理
①区间加法
②区间减法使用方法①②,只要能搞掂一个端点的改变对所有函数值变化的一般规律即可。通常可以快速变化的函数是具有单调性的,如本题的 mex 函数。
mex 函数的两个经验:
①具有单调性
②求 nxt 数组