• [bzoj2120] 数颜色


    Description

    墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

    Input

    第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

    Output

    对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

    Sample Input

    6 5 
    1 2 3 4 5 5
    Q 1 4
    Q 2 6
    R 1 2
    Q 1 4
    Q 2 6
    

    Sample Output

    4
    4
    3
    4
    

    HINT

    对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

    solution

    (pre_i)表示在当前点左边和当前点颜色相同并且和当前点距离最近的点。

    那么对于Q x y,答案为:

    [sum_{i=x}^{y}[pre_i<x] ]

    那么可以转化为求一个区间内小于(x)的数有多少个,那么拿个树状数组套权值线段树或树状数组套平衡树或线段树套平衡树什么的维护下都行。(后面两个没写过,不知道常数足不足以通过)

    对于(pre_i),可以开(1e5)(set)维护下就行了。

    不要瞎用static!!!(我被坑了好久)

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
    	x=0;int f=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
    	if(x<0) putchar('-'),x=-x;
    	if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e5+1;
    
    int col,n,m,pre[maxn],arr[maxn];
    map<int,int > mp;
    set<int > s[maxn];
    
    #define mid ((l+r)>>1)
    
    int ls[maxn*100],rs[maxn*100],sum[maxn*100],tot;
    
    struct Segment_Tree {
    	int rt;
    	void modify(int &p,int l,int r,int x,int v) {
    		if(!p) p=++tot;
    		if(l==r) {sum[p]+=v;return ;}
    		if(x<=mid) modify(ls[p],l,mid,x,v);
    		else modify(rs[p],mid+1,r,x,v);
    		sum[p]=sum[ls[p]]+sum[rs[p]];
    	}
    	int query(int p,int l,int r,int x) {
    		if(!p||l==r) return 0;
    		if(x<=mid) return query(ls[p],l,mid,x);
    		else return query(rs[p],mid+1,r,x)+sum[ls[p]];
    	}
    };
    
    struct Binary_Indexed_Tree {
    	Segment_Tree sgt[maxn];
    	void modify(int p,int x,int v) {
    		for(;p<=n;p+=p&-p) sgt[p].modify(sgt[p].rt,0,n+m,x,v);
    	}
    	int query(int r,int x) {
    		int ans=0;
    		for(;r;r-=r&-r) ans+=sgt[r].query(sgt[r].rt,0,n+m,x);
    		return ans;
    	}
    }BIT;
    
    int main() {
    	read(n),read(m);
    	//for(int i=1;i<maxn;i++) s[i].insert(0),s[i].insert(maxn);
    	for(int i=1,c;i<=n;i++) {
    		read(c),c=(mp[c]?mp[c]:(mp[c]=++col));
    		if(!s[c].empty()) {
    			set<int>::iterator t=s[c].end();--t;
    			pre[i]=*t;
    		}
    		s[c].insert(i),arr[i]=c;
    		BIT.modify(i,pre[i],1);
    	}
    	for(int i=1;i<=m;i++) {
    		char ss[5];int x,y;scanf("%s",ss+1);read(x),read(y);
    		if(ss[1]=='Q') write(BIT.query(y,x)-x+1);
    		else {
    			y=mp[y]?mp[y]:(mp[y]=++col);
    			set<int> :: iterator t=s[arr[x]].find(x);++t;
    			if(t!=s[arr[x]].end()) {
    				BIT.modify(*t,pre[*t],-1);
    				pre[*t]=pre[x];
    				BIT.modify(*t,pre[*t],1);
    			}
    			s[arr[x]].erase(x),arr[x]=y,s[arr[x]].insert(x);
    			t=s[y].find(x);
    			BIT.modify(x,pre[x],-1);
    			if(t!=s[arr[x]].begin()) t--,pre[x]=*t,t++;else pre[x]=0;
    			BIT.modify(x,pre[x],1);t++;
    			if(t!=s[arr[x]].end()) {
    				int now=*t;
    				BIT.modify(now,pre[now],-1);
    				pre[now]=x;
    				BIT.modify(now,pre[now],1);
    			}
    			//for(int i=1;i<=n;i++) printf("%d ",pre[i]);puts("");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    剑指offer系列——41.和为S的连续正数序列
    剑指offer系列——40.数组中只出现一次的数字i-ii
    指针初始化
    剑指offer系列——39.平衡二叉树
    剑指offer系列——38.二叉树的深度
    剑指offer系列——37.数字在排序数组中出现的次数/在排序数组中查找元素的第一个和最后一个位置
    剑指offer系列——36.两个链表的第一个公共结点?
    剑指offer系列——35.数组中的逆序对**
    查看机器上GPU情况
    Linux下fork()、vfork()、clone()和exec()的区别
  • 原文地址:https://www.cnblogs.com/hbyer/p/10109666.html
Copyright © 2020-2023  润新知