主席树
设nt[i]表示v[i]这个数下一个出现的位置,没有的话就是n+1
题目就转化为求区间[l,r]之间nt[i]>=r+1的数字个数
这就可以弄个权值线段树,询问区间和
不知道为什么我的动态开点开了1e7会还不够(好像是爆数组TLE)
gyz大佬帮我把我的主席树改成指针写法才A了qwq
/**************************************************************
Problem: 1878
User: syh0313
Language: C++
Result: Accepted
Time:2924 ms
Memory:22068 kb
****************************************************************/
#include
#include
#include
#include
#include
#include
#define lch n->lc
#define rch n->rc
using
namespace
std;
const
int
maxn=500010;
int
n,m,v[maxn],nt[maxn];
struct
da{da*lc,*rc;
int
sum;
da(){lc=rc=0;sum=0;}
};da*root[maxn];
map<
int
,
int
>st;
void
build_tree(da*&n,
int
l,
int
r)
{
if
(!n)n=
new
da;
n->sum=0;
if
(l==r)
return
;
int
mid=(l+r)>>1;
build_tree(lch,l,mid); build_tree(rch,mid+1,r);
}
void
updata(da*&n){n->sum=lch->sum+rch->sum;}
void
tree_add(da*&old,da*&n,
int
l,
int
r,
int
lc)
{
n=
new
da;
if
(l==r && l==lc) {n->sum=old->sum+1;
return
;}
int
mid=(l+r)>>1;
if
(lc<=mid) {rch=old->rc; tree_add(old->lc,lch,l,mid,lc);}
else
{lch=old->lc; tree_add(old->rc,rch,mid+1,r,lc);}
updata(n);
}
int
qury(da*&old,da*&n,
int
L,
int
R,
int
l,
int
r)
{
if
(L==l && R==r)
return
n->sum-old->sum;
int
mid=(L+R)>>1;
if
(r<=mid)
return
qury(old->lc,lch,L,mid,l,r);
else
if
(l>=mid+1)
return
qury(old->rc,rch,mid+1,R,l,r);
return
qury(old->lc,lch,L,mid,l,mid)+qury(old->rc,rch,mid+1,R,mid+1,r);
}
int
main()
{
scanf
(
"%d"
,&n);
for
(
int
i=1;i<=n;i++)
scanf
(
"%d"
,&v[i]),st[v[i]]=n+1;
for
(
int
i=n;i>=1;i--) nt[i]=st[v[i]],st[v[i]]=i;
build_tree(root[0],1,n+1);
for
(
int
i=1;i<=n;i++) {
tree_add(root[i-1],root[i],1,n+1,nt[i]);
}
int
num;
scanf
(
"%d"
,&num);
for
(
int
i=1;i<=num;i++)
{
int
l,r;
scanf
(
"%d%d"
,&l,&r);
printf
(
"%d\n"
,qury(root[l-1],root[r],1,n+1,r+1,n+1));
}
return
0;
}