洛谷mNOIP模拟赛Day1-数颜色

Posted white_hat_hacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷mNOIP模拟赛Day1-数颜色相关的知识,希望对你有一定的参考价值。

传送门

题目大意:

给定一个序列,维护每个数字在[L,R]出现的次数以及交换a[x]和a[x+1]的操作

一开始想的分桶法,感觉复杂度还可以吧,常数有点大,于是死得很惨(65分)

技术分享
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<map>
  7 #include<set>
  8 #include<queue>
  9 #include<vector>
 10 #define INF 0x7f7f7f7f
 11 #define pii pair<int,int>
 12 #define ll long long
 13 #define SIZE 2505
 14 #define MAXN 300005
 15 using namespace std;
 16 
 17 int read(){
 18     int x=0,f=1;char ch=getchar();
 19     while(ch<0||ch>9){if(-==ch)f=-1;ch=getchar();}
 20     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
 21     return x*f;
 22 }
 23 int n,num,len;
 24 struct Bucket{
 25     int L;
 26     int a[SIZE];
 27     vector<int> v;
 28     Bucket(){
 29         L=-1;
 30         memset(a,0,sizeof(a));
 31     }
 32     void add(int x){
 33         a[++L]=x;
 34         vector<int>::iterator P=lower_bound(v.begin(),v.end(),x);
 35         v.insert(P,x);
 36     }
 37 }s[250];
 38 //pos:id->position 
 39 //id:
 40 int main()
 41 {
 42 //    freopen("data.in","r",stdin);
 43 //    freopen("my.out","w",stdout);
 44     n=read();int T=read();
 45     len=pow(1.0*n,0.618);
 46     num=(n-1)/len;
 47     for(int i=0;i<n;i++){
 48         s[i/len].add(read());
 49     }
 50     while(T--){
 51         int p=read();
 52         int numl=0,numr=0,posl=0,posr=0;
 53         if(1==p){
 54             int ans=0;
 55             int l=read(),r=read(),c=read();
 56             l--,r--;
 57             numl=l/len,numr=r/len;
 58             posl=l%len,posr=r%len;
 59             if(numl!=numr){
 60                 for(int i=numl+1;i<numr;i++){
 61                     ans+=upper_bound(s[i].v.begin(),s[i].v.end(),c)-lower_bound(s[i].v.begin(),s[i].v.end(),c);
 62                 }
 63                 for(int i=posl;i<=s[numl].L;i++){
 64                     if(s[numl].a[i]==c){
 65                         ans++;
 66                     }
 67                 }
 68                 for(int i=0;i<=posr;i++){
 69                     if(s[numr].a[i]==c){
 70                         ans++;
 71                     }
 72                 }
 73             }
 74             else{
 75                 for(int i=posl;i<=posr;i++){
 76                     if(s[numl].a[i]==c){
 77                         ans++;
 78                     }
 79                 }
 80             }
 81             printf("%d\n",ans);
 82         }
 83         else{
 84             int l=read()-1,r=l+1;
 85             numl=l/len,numr=r/len;
 86             posl=l%len,posr=r%len;
 87             int lc=s[numl].a[posl],rc=s[numr].a[posr];
 88             if(lc==rc){
 89                 continue;
 90             }
 91             vector<int>::iterator it;
 92             it=lower_bound(s[numl].v.begin(),s[numl].v.end(),lc);
 93             s[numl].v.erase(it);
 94             it=lower_bound(s[numl].v.begin(),s[numl].v.end(),rc);
 95             s[numl].v.insert(it,rc);
 96             it=lower_bound(s[numr].v.begin(),s[numr].v.end(),rc);
 97             s[numr].v.erase(it);
 98             it=lower_bound(s[numr].v.begin(),s[numr].v.end(),lc);
 99             s[numr].v.insert(it,lc);
100             swap(s[numl].a[posl],s[numr].a[posr]);
101 //            for(int i=0;i<=num;i++){
102 //                for(int j=0;j<s[i].v.size();j++){
103 //                    printf("%d ",s[i].v[j]);
104 //                }
105 //                printf("\n");
106 //            }
107 //            printf("\n");
108         }
109     }
110     return 0;
111 }
分桶

其实直接记录下每个数字出现的位置放到vector里面然后二分一下就可以了,

思路很简单,正如管理员说的“很多人学数据结构学傻了”,简单的问题不需要那么麻烦的

不过这题有个小坑,编号指的就是从左向右数第几个,不是兔子的属性

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<vector>
 6 #define MAXN 300005
 7 using namespace std;
 8 int n;
 9 vector<int> s[MAXN];
10 int read(){
11     int x=0;char ch=getchar();
12     while(ch<0||ch>9){ch=getchar();}
13     while(ch>=0&&ch<=9){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
14     return x;
15 }
16 void write(int x){
17     if(!x){
18         putchar(48);
19         putchar(\n);
20         return;
21     }
22     char t[10]={0};
23     int cnt=0;
24     while(x){
25         t[++cnt]=x%10;
26         x/=10;
27     }
28     for(int i=cnt;i>=1;i--){
29         putchar(48+t[i]);
30     }
31     putchar(\n);
32 }
33 int a[MAXN];
34 int main()
35 {
36 //    freopen("color2.in","r",stdin);
37     n=read();
38     int T=read();
39     for(int i=1;i<=n;i++){
40         a[i]=read();
41         s[a[i]].push_back(i);
42     }
43     while(T--){
44         int p=read();
45         if(p==1){
46             int l=read(),r=read(),c=read();
47             write(upper_bound(s[c].begin(),s[c].end(),r)-lower_bound(s[c].begin(),s[c].end(),l));
48         }
49         else{
50             int l=read(),r=l+1;
51             if(a[l]==a[r]){
52                 continue;
53             }
54             int P1=lower_bound(s[a[l]].begin(),s[a[l]].end(),l)-s[a[l]].begin();
55             int P2=lower_bound(s[a[r]].begin(),s[a[r]].end(),r)-s[a[r]].begin();
56             s[a[l]][P1]=r;
57             s[a[r]][P2]=l;
58             swap(a[l],a[r]);
59         }
60     }
61     return 0;
62 }
AC

有点卡常

总的来说这题出的还算不错的,很灵活的数据结构

 

以上是关于洛谷mNOIP模拟赛Day1-数颜色的主要内容,如果未能解决你的问题,请参考以下文章

洛谷mNOIP模拟赛Day1-斐波那契

洛谷mNOIP模拟赛Day1T1 斐波那契

2017.11.2洛谷 mNOIP 比赛 | T1 斐波那契找规律

mNOIP模拟赛Day 1 T2 数颜色

洛谷mNOIP模拟赛Day2-将军令

洛谷mNOIP模拟赛Day2-入阵曲