http://www.lydsy.com/JudgeOnline/problem.php?id=1878
https://www.luogu.org/problem/show?pid=1972
隔了一段时间用新方法重做此题。。。
这个可以看做离线区间查询问题,一段时间以前,我把这题当做是线段树来做
具体思路:把询问按照右端点从小到大排序,然后一个一个插入
意思是说按照项链的真实情况插入
插入某种编号的贝壳时,如果这种编号之前已经插入过了,那么就把之前插入过的贝壳删除
如果插入的节点是某一询问的右端点,处理询问
显然是对的不是吗
线段树也可用树状数组代替
贴一下线段树代码
#include
#include
#include
#include
using namespace std;
struct ppap{
int x,y,b;
}p[400001];
int n,a[400001],t[400001],ans[400001],la[1000001]={0};
inline bool cmp(ppap x,ppap y){
if(x.yreturn true;
if(x.y==y.y&&x.xreturn true;
return false;
}
inline void xg(int l,int r,int i,int p,int nod){
if(l==i&&r==i)t[nod]=p;
else{
int m=(l+r)/2;
if(i>m)xg(m+1,r,i,p,nod*2+1);
else xg(l,m,i,p,nod*2);
t[nod]=t[nod*2]+t[nod*2+1];
}
}
inline int s(int l,int r,int i,int j,int nod){
if(l==i&&r==j)return t[nod];
int m=(l+r)/2;
if(j<=m)return s(l,m,i,j,nod*2);
if(i>=m+1)return s(m+1,r,i,j,nod*2+1);
int le=s(l,m,i,m,nod*2),re=s(m+1,r,m+1,j,nod*2+1);
return le+re;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int m;scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&p[i].x,&p[i].y);
p[i].b=i;
}
sort(p+1,p+m+1,cmp);
int pp=1;
for(int i=1;i<=n;i++){
xg(1,n,i,1,1);
if(la[a[i]]!=0)xg(1,n,la[a[i]],0,1);
la[a[i]]=i;
while(p[pp].y==i){
ans[p[pp].b]=s(1,n,p[pp].x,p[pp].y,1);
pp++;
}
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
一段时间以后发现这题可以轻松用莫队水过。。。
直接分块暴力跑得比常数大的线段树快呢!!!
#include
using namespace std;
struct ppap{
int x,y,k,b;
}a[100001];
int s[1000001];
int n,m,p[100001],ans[100001];
inline bool cmp(ppap a,ppap b){return a.k==b.k?a.yinline void work(){
int l=1,r=0,now=0;
for(int i=1;i<=m;i++){
while(lif(s[p[l]]==0)now--;l++;}
while(r>a[i].y){s[p[r]]--;if(s[p[r]]==0)now--;r--;}
while(l>a[i].x){s[p[l-1]]++;if(s[p[l-1]]==1)now++;l--;}
while(r1]]++;if(s[p[r+1]]==1)now++;r++;}
ans[a[i].b]=now;
}
}
int main()
{
scanf("%d",&n);
int t=sqrt(n);
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].b=i;
a[i].k=(a[i].x-1)/t+1;
}
sort(a+1,a+m+1,cmp);
work();
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}