传送门
题目大意:
给定一个序列,维护每个数字在[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
有点卡常
总的来说这题出的还算不错的,很灵活的数据结构
时间: 2024-11-07 12:11:25