Codeforces Round #590 (Div. 3)

https://codeforces.com/contest/1234

 

D:给定一个字符串操作1更改该位置上的字符,2输出区间内有几个不同的字符

正常写法应该是线段树和树状数组,不过我忘了怎么写。。。用set可以做,以数字代替字母,'a'-0,'b'-1这样表示,在该字母表示的set容器插入出现该字母的所有位置

set用insert插入

例如:set<int>vis[30];这样表示有30个set容器;

本题有两个步骤:

(1)每更新一个元素,就删除原本在容器里面的相应位置,在新的容器里面插入该位置;

(2)最后通过迭代器访问区间,当然不是真正意义上的查询区间,区间为[L,R]通过lower_bound(L)查询每一个容器里面是否存在位置>=L的字母,这样就可以直接避免了去重,因为一个字母容器里面只会查询到一个数组下标>=L的该字母

需要注意的是 二分查找一个有序数列,返回第一个大于等于x的数,如果没找到,返回末尾的迭代器位置

也就是说如果在某一个字母容器查询不到在区间[L,R]的位置,会返回setname.end(),每一次二分查找的时候判断一下即可,否则查询不到他仍然会返回一个数,即该容器的数组下标

#include<bits/stdc++.h>

using namespace std;
typedef long long ll; 
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
/*------------------------------------------------------------------------*/
const int maxn=1e5; 
char s[maxn];
int main( )
{	
	//ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    //freopen("a.txt","r",stdin);
    //freopen("a.txt","w",stdout);
    
    set<int>vis[30];
   
    //cin>>str;
    scanf("%s",s+1);
    
    for(int i=1;s[i];++i){
    	
    	vis[s[i]-'a'].insert(i);
    }
	int q;
    int op;
    cin>>q;
    //set会自动排序 
    while(q--){
    	//cin>>op;
    	scanf("%d",&op);
    	if(op==1){
    		
    		int pos;//位置
			char ch;//插入的字符
			//cin>>pos>>ch;
			scanf("%d %c",&pos,&ch); 
			vis[s[pos]-'a'].erase(pos); //先清空原本在此位置的字符 
			
    		vis[ch-'a'].insert(pos);
			s[pos]=ch; 
    	}
    	else if(op==2){
    			
    		int ans=0;
    		int l,r;
    		//cin>>l>>r;
    		scanf("%d %d",&l,&r); 
    		for(int i=0;i<26;++i){
    			
    			set<int>::iterator it=vis[i].lower_bound(l);
    			
    			if(it==vis[i].end())continue;
    			
    			if(*it>=l&&*it<=r){
    					ans++;
    			}
    			
    			/*for(int j=l;j<=r;++j){
    				set<int>::iterator it=vis[i].find(j); 
    				if((*it)==i)continue;
    				if(*it>=l&&*it<=r){
    					ans++;
    					break;
    				}
    			}*/
    			
    		}
    		cout<<ans<<endl;
    	}
    }
    
    
    
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值