题解:[SDOI2009]HH的项链
刚开始暴力开数组打标记的方法水过四十分,代码是这样的
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int a[500005], num[1000005]; 6 int m, n, l, r, ans; 7 int read(){ 8 int x=0,f=1; 9 char c=getchar(); 10 while(c>'9'||c<'0') { 11 if(c=='-')f=-1; 12 c=getchar(); 13 } 14 while(c>='0'&&c<='9') 15 x=x*10+c-'0',c=getchar(); 16 return x*f; 17 } 18 int main(){ 19 n=read(); 20 for(int i=1; i<=n; i++){ 21 a[i]=read(); 22 } 23 m=read(); 24 while(m--){ 25 ans=0; 26 memset(num, 0, sizeof(num)); 27 l=read(); 28 r=read(); 29 for(int i=l; i<=r; i++){ 30 if(!num[a[i]]){ 31 ans++; 32 num[a[i]]=1; 33 } 34 } 35 printf("%d\n",ans); 36 } 37 return 0; 38 }
其实这题有好多做法,线段树,树状数组,莫队啊qwq
暴力的话可以使用莫队来做
离线的话可以使用排序加树状数组或者线段树来做
强制在线可以使用主席树来做
这是八十分的莫队(据书名号大爷说努力努力改改快读改改块的大小就卡过了qwq,然而我懒不想改……)
可能洛谷强化数据后卡了莫队两个点qwq
算是莫队入门题
先按照区间左右端点排序然后依次处理,挺好理解的
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 int sum, tot[1000010], ans[2000010], color[500010], pos[500010]; 8 struct node{ 9 int l, r, id; 10 }ask[2000010]; 11 int n, m, qwq, L, R; 12 int read(){ 13 int s=0,fh=1;char ch=getchar(); 14 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 15 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 16 return s*fh; 17 } 18 bool cmp(node a,node b){ 19 if(pos[a.l]==pos[b.l]) return a.r<b.r; 20 return a.l<b.l; 21 } 22 void del(int C){ tot[C]--; if(tot[C]==0) sum--;} 23 void add(int C){ tot[C]++; if(tot[C]==1) sum++;} 24 int main(){ 25 n=read(); 26 for(int i=1; i<=n; i++) color[i]=read(); 27 qwq=(int)sqrt(n); 28 m=read(); 29 for(int i=1; i<=m; i++){ 30 ask[i].l=read(); 31 ask[i].r=read(); 32 ask[i].id=i; 33 } 34 for(int i=1; i<=n; i++) pos[i]=(int)(i-1)/qwq+1; 35 sort(ask+1, ask+m+1, cmp); 36 L=1; 37 R=0; 38 memset(tot, 0, sizeof(tot)); 39 for(int i=1; i<=m; i++){ 40 while(L<ask[i].l){ 41 del(color[L]); 42 L++; 43 } 44 while(L>ask[i].l){ 45 L--; 46 add(color[L]); 47 } 48 while(R<ask[i].r){ 49 R++; 50 add(color[R]); 51 } 52 while(R>ask[i].r){ 53 del(color[R]); 54 R--; 55 } 56 ans[ask[i].id]=sum; 57 } 58 for(int i=1; i<=m; i++) printf("%d\n",ans[i]); 59 return 0; 60 }
接下来是能A过这道题的线段树orzzz
求和函数一个大于小于号卡了我一个小时qwq真是绝望
最近总是在疯狂RE和MLE中徘徊
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int maxn=500005; 6 int sum[maxn*4], n, m, color[maxn], cnt, ans[maxn], last[maxn*2]; 7 struct node{ 8 int l, r, id; 9 }ask[maxn]; 10 bool cmp(node a,node b){ 11 if(a.r==b.r) return a.l<b.l; 12 return a.r<b.r; 13 } 14 void pushup(int rt){ 15 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 16 } 17 void update(int x, int c, int l, int r, int rt){ 18 if(l==r && x==l){ 19 sum[rt]=c; 20 return; 21 } 22 int mid=(l+r)>>1; 23 if(x<=mid) update(x, c, l, mid, rt<<1); 24 else update(x, c, mid+1, r, rt<<1|1); 25 pushup(rt); 26 } 27 int query(int L, int R, int l, int r, int rt){ 28 if(L<=l && r<=R) return sum[rt]; 29 int mid=(l+r)>>1; 30 int ans=0; 31 if(L<=mid) ans+=query(L, R, l, mid, rt<<1); 32 if (R>mid) ans+=query(L, R, mid+1, r, rt<<1|1); 33 return ans; 34 } 35 int main(){ 36 scanf("%d",&n); 37 for(int i=1; i<=n; i++) scanf("%d",&color[i]); 38 scanf("%d",&m); 39 for(int i=1; i<=m; i++){ 40 scanf("%d%d",&ask[i].l,&ask[i].r); 41 ask[i].id=i; 42 } 43 sort(ask+1, ask+m+1, cmp); 44 cnt=1; 45 for(int i=1; i<=n; i++){ 46 update(i, 1, 1, n, 1); 47 if(last[color[i]]) update(last[color[i]], 0, 1, n, 1); 48 last[color[i]]=i; 49 while(ask[cnt].r==i){ 50 ans[ask[cnt].id]=query(ask[cnt].l, ask[cnt].r, 1, n, 1); 51 cnt++; 52 } 53 } 54 for(int i=1; i<=m; i++) printf("%d\n",ans[i]); 55 return 0; 56 }
然后是主席树做法,先去吃饭qwq,等会儿回来更
"Hello World!"