1. 程式人生 > >bzoj 2120 數顏色 樹狀陣列套可持久化資料結構。

bzoj 2120 數顏色 樹狀陣列套可持久化資料結構。

查詢區間l,r 中 不同值的個數, 修改操作是 單點更新。

如果沒有更新,此題直接 離線。

有更新的話,就只有 樹狀陣列套 平衡樹 或者 可持久化資料結構。

問題一 。統計 在 【1,l-1】中都多少個值沒有出現在 【l,r】。也就是統計 【1,l-1】中有多少個值,在【1,r】中僅出現在 【1,l-1】。

統計 對於ai ,它的下次出現與ai 值相同的點的下標是多少。 相當於 把所有相同的值的下標放到同一棵set 中,查 i 的後繼是多少。

所以按值構建2*n 棵set ,來維護2*n個值出現的下標。快速的找到後繼。(值是離散化後的值,下標i,離散化後值 a, 那麼st【a】中插入 i)。

序列n個點, 共n個線段樹, 每個線段樹中維護的是 是 又是後繼的下標, 有點繞。

查詢  【1,l-1】 查大於r的值有多少個,就是 問題一的解。

問題二 : 在區間 【1,r】中出現了多少個值, 在set 中查詢如果是 begin() , 就是說最小的數, 那麼+1 ,不是最小不加。

修改是個難點 :

問題一種 維護的是後繼, 相當與 連結串列的修改,

刪除點 a ,它的前驅的後繼發生變化。

增添點a,增添後的前驅的後繼也發生變化。

他這個點的前驅和後繼發生變化。

這樣 共需要 6次操作。

問題二中較簡單。

這題AC的歷程有點艱辛。 程式碼有點長

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <cstring>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <assert.h>
#include <queue>
#define REP(i,n) for(int i=0;i<n;i++)
#define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)
#define ALLL(x) x.begin(),x.end()
#define SORT(x) sort(ALLL(x))
#define CLEAR(x) memset(x,0,sizeof(x))
#define FILLL(x,c) memset(x,c,sizeof(x))
using namespace std;
const double eps = 1e-9;
#define LL long long 
#define pb push_back
const int maxn  = 11000;
int num[maxn];
int n , m;
map<int ,int>mp;
map<int,int>::iterator it;
char op[maxn][4];
int t[maxn][3];
struct Node{
    Node *l,*r;
    int sum;
};
int tot;
struct Seg{
	Node nodes[maxn*60];
	Node *null;
	Node *root[maxn];
	int C;
	void init(){
          C= 0;
          null = &nodes[C++];
          null->l = null ->r = null;
          null->sum = 0;
          for(int i=1;i<=n;i++){
          	          root[i] = &nodes[C++];  
                      root[i]->l = null;  
                      root[i]->r = null;  
                      root[i]->sum  = 0; 
          }
	}
	Node *update(int pos,int left,int right,Node *root,int val){
       Node * rt = root;  
       if(rt == null){  
           rt = &nodes[C++];  
           rt->l = null;  
           rt->r = null;  
           rt->sum = 0;  
       }  
       if(left == right){  
            rt->sum +=val;  
            return rt;  
       }  
       int mid = (left + right)/2;  
       if(pos<=mid){  
          rt->l = update(pos,left,mid,rt->l,val);  
       }else{  
          rt->r = update(pos,mid+1,right,rt->r ,val);  
       }  
       rt->sum = rt->l->sum + rt->r->sum ;
       return rt;  
    }
    void update(int k,int pos,int val){
    	 for(;k<=n;k+= k&(-k)){
    	 	update(pos,1,n+1,root[k],val);
    	 }
    }
    int  query(int left ,int right,int L,int R,Node *root){
    	if(L>R)return 0;
    	  if(L<=left && right<=R){
    	  	   return root->sum;
    	  }
    	  int mid = (left +right)/2;
    	  int ret = 0;
    	  if(L<=mid){
    	  	  ret += query(left,mid,L,R,root->l);
    	  }
    	  if(R>=mid){
    	  	  ret += query(mid+1,right,L,R,root->r);
    	  }
    	  return ret;
    }
    // 大於等於 a 的值 有多少個
    int get(int k,int a){
    	 int sum = 0 ;
    	 for(;k>0;k-=k&(-k)){
    	 	 sum += query(1,n+1,a,n+1,root[k]);
    	 }
    	 return sum;
    }
}S1,S2;
set<int>st[maxn*2];
set<int>::iterator it1,it2,it3;

int arr[maxn*2];
void inc(int k,int val){
	if(k==0)return ;
	for(;k<=n;k+=k&(-k)){
		arr[k]+=val;
	}
}
int get(int k){
	int sum = 0;
	for(;k>0;k-=k&(-k)){
		sum += arr[k];
	}
	return sum;
}
void solve(){
	S1.init();
	//cout << "*********"<<endl;
	CLEAR(arr);
	for(int i=1;i<=tot;i++){
		st[i].clear();
		st[i].insert(n+1);
	}
	for(int i=1;i<=n;i++){
		 st[mp[num[i]]].insert(i);
	}
	// 初始化 arr
	for(int i=1;i<=n;i++){
	      int v = mp[num[i]];
	      it1 =st[v].lower_bound(i);
	      if(it1==st[v].begin()){
	      //	cout << i<< "***"<<endl;
	      	 inc(i,1);
	      }
    }
	for(int i=1;i<=n;i++){
		 int v = mp[num[i]];
	     it1 = st[v].upper_bound(i);
	     S1.update(i,(*it1),1);
	     //cout <<i  << "  "<< (int)(*it1)<<endl;
	}
	for(int i=1;i<=m;i++){
	//	cout << "starti"<<i<<endl;
		  if(op[i][0]=='Q'){
		  	  int l = t[i][0];
		  	  int r = t[i][1];
		  //	  cout <<r << " wtf" <<mp[r]<<endl;
		  	  int ans1 = S1.get(l-1,r+1);
		  	  int ans2 = get(r);
		  	 
		  	  int ans = ans2 -ans1;
		  	 // cout << ans2 << " "<< ans1<<endl;
		  	  printf("%d\n",ans);
		  }else{
		  	  int id = t[i][0];
		  	  int val = t[i][1];
		  	  if(num[id]==val)continue;
		  	  // 實現 刪除。
		  	  int v = mp[num[id]];
		  	  it1 = st[v].lower_bound(id);
		  	  if(it1==st[v].begin()){
		  	  	 inc(id,-1);
		  	  	 it1++;
		  	  	 inc((*it1),1);
		  	  }
		  	  // SEGMENT 
		  	  it3 =it2 = it1 = st[v].lower_bound(id);
		  	  it2++;
		  	  S1.update(id,(*it2),-1);
		  	  if(it1 != st[v].begin()){
		  	  	   it1--;
		  	       S1.update((*it1),id,-1);
		  	       S1.update((*it1),(*it2),1);
		  	  }
		  	  st[v].erase(it3);
		  	  //geng新arr
		  	  
		  	  // 實現增添。
		  	  num[id] = val;
		  	  v = mp[num[id]];
		  	  st[v].insert(id);
		  	  //gengxin arr
		  	  it1 =st[v].lower_bound(id);
		  	  if(it1==st[v].begin()){
		  	  	  inc(id,1);
		  	  	  it1++;
		  	  	  inc((*it1),-1);
		  	  }//SEGMENT
		  	  it2 = it1 = st[v].lower_bound(id);
		  	  it2++;
		  	  if(it1 != st[v].begin()){
		  	        it1--;
		  	        S1.update((*it1),(*it2),-1);
		  	        S1.update((*it1),id,1);
		  	  }
		  	  S1.update(id,(*it2),1);
		  	  
		 }
	}
}
int idx[maxn*2];
int main(){
    while(~scanf("%d%d",&n,&m)){
    	mp.clear();
    	for(int i=1;i<=n;i++){
    		scanf("%d",&num[i]);
    		mp[num[i]]=1;
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%s",op[i]);
    		if(op[i][0]== 'Q'){
    			 scanf("%d%d",&t[i][0],&t[i][1]);
    			 mp[t[i][1]]=1;
    		}else{
    			scanf("%d%d",&t[i][0],&t[i][1]);
    			mp[t[i][1]]=1;
    		}
    	}
    	tot = 0;
    	for(it = mp.begin(); it!= mp.end();it++){
    		 tot ++ ;
    		 it->second = tot;
    		 idx[tot] = it->first;
    	}
    	
    	tot++;
    	solve();
    }   
    return 0;
}