【SDOI2009】HH的项链

我的思维能力果然在提高呢

原题:

 n<=10^6

区间不同种类颜色数,看上去很棘手啊

普通的线段树思想是做不了的,因为区间不同种类颜色数这玩意没法进行合并

那必须转化思维角度

中间各种错误的处理方式不赘述了hhh

最后还是偶然碰到了正解

这题没有修改操作,那可以离线呀,区间按左端点排序

然后惊喜地发现,按左端点递增的顺序枚举区间,那么某个区间左边的颜色都不考虑

右边的颜色我们可以只考虑离左端点最近的

因为如果更远的颜色在区间内,那么更近的相同颜色一定在区间内

所以一开始线段树里所有颜色第一次出现的位置为1,其他为0

按左端点递增枚举区间,每次区间左端点+1,就对于原先在左端点的颜色,找到它在序列中的后一个位置,在线段树中把这个位置权值设为1

表示我们开始考虑这个位置上的颜色

然后求查询区间的和

总结一下,这题本质是强调性质:求区间不同颜色个数,只需要考虑在左端点之后的所有颜色中,第一个出现的颜色,统计区间中有多少个这样的颜色

然后题目没有操作的性质能让我们离线排序询问区间,使得能够方便地选出左端点之后的所有颜色

使用离线排序获得性质

这题大概也能提炼出“思考特殊位置元素”的思维方式吧hhh

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int rd(){int z=0,mk=1;  char ch=getchar();
 6     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
 7     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
 8     return z*mk;
 9 }
10 struct nds{int x,y,z;}b[1100000];
11 int n,m,a[1100000];
12 int nxt[1100000],lst[1100000];
13 int v[4100000];
14 int ans[11000000];
15 void mdf(int x,int l,int r,int y,int z){
16     if(l==r){
17         v[x]+=z;
18         return ;
19     }
20     int md=(l+r)>>1;
21     if(y<=md)  mdf(x<<1,l,md,y,z);
22     else  mdf(x<<1|1,md+1,r,y,z);
23     v[x]=v[x<<1]+v[x<<1|1];
24 }
25 int qry(int x,int l,int r,int ql,int qr){
26     if(l==ql && r==qr)  return v[x];
27     int md=(l+r)>>1;
28     if(ql<=md && qr>md)  return qry(x<<1,l,md,ql,md)+qry(x<<1|1,md+1,r,md+1,qr);
29     else if(qr<=md)  return qry(x<<1,l,md,ql,qr);
30     else  return qry(x<<1|1,md+1,r,ql,qr);
31 }
32 bool cmp(nds x,nds y){  return x.x==y.x ? x.y<y.y : x.x<y.x;}
33 int main(){
34     cin>>n;
35     for(int i=1;i<=n;++i){
36         a[i]=rd();
37         if(lst[a[i]])  nxt[lst[a[i]]]=i;
38         else  mdf(1,1,n,i,1);
39         lst[a[i]]=i;
40     }
41     cin>>m;
42     for(int i=1;i<=m;++i)  b[i].x=rd(),b[i].y=rd(),b[i].z=i;
43     sort(b+1,b+m+1,cmp);
44     int tmp=0;
45     for(int i=1;i<=m;++i){
46         for(;tmp<b[i].x;++tmp)if(nxt[tmp])
47             mdf(1,1,n,nxt[tmp],1);
48         ans[b[i].z]=qry(1,1,n,b[i].x,b[i].y);
49     }
50     for(int i=1;i<=m;++i)  printf("%d\n",ans[i]);
51     return 0;
52 }
View Code

猜你喜欢

转载自www.cnblogs.com/cdcq/p/11984554.html