bzoj 2120 數顏色 樹狀陣列套可持久化資料結構。
阿新 • • 發佈:2019-01-23
查詢區間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; }