P2464 [SDOI2008]鬱悶的小J [樹狀陣列+離線]
阿新 • • 發佈:2018-12-15
樹狀陣列好題
如果按照題意直接做,也就是線上演算法,用任何一種資料結構都
難以實現,需要“樹套樹”即可持久化資料結構。
• 本題需要使用離線演算法。也就是將所有詢問先讀進來再進行處理。
• 所謂“更改書”,可以理解為兩種操作:先將原來的書刪除,再
插入新的書
• 假設只有一種書(思維減法),那麼只需要維護三種操作:
• 在第i個位置插入書/在第i個位置刪除書。
• 詢問第i..j的位置有幾本書
• 用樹狀陣列可以輕鬆實
• 如何處理多種書的情況?
• 發現一個規律:無論是插入還是刪除第2種書,對於第1種的詢問都沒有任何影響。
• 因此只要將所有操作按照書的種類排序,分別處理即可
• 總結起來就是:
• 首先將修改操作拆成刪除舊書、插入新書兩種。加上詢問,共有三種操作。每種操作還需要記錄時間,也就是它是第幾個操作。
• 將三種操作按照第一關鍵字書的種類、第二關鍵字時間進行排
• 使用樹狀陣列維護插入、刪除、詢問三種操作。
• 由於按照種類排序,因此可以保證在任何時刻,樹狀陣列中的書都是同一類的(一類一類的完成)。
• 完成所有訊問後,將詢問操作排回原來的順序,輸出答案
#include<bits/stdc++.h> #define N 100050*4 using namespace std; struct Node{ int time,id,op,kind,l,r; // 1-delete , 2 - add 3 - quary }Q[N]; int n,m,tot,a[N],c[N],ans[N],cnt; bool cmp(Node a,Node b){ if(a.kind==b.kind) return a.time<b.time; return a.kind<b.kind; } void Up(int x,int val){for(;x<=n;x+=x&-x) c[x] += val;} int Qu(int x){int ans=0; for(;x;x-=x&-x) ans += c[x]; return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); Q[++tot] = Node{0,0,2,a[i],i,0}; } for(int i=1;i<=m;i++){ char s[3]; scanf("%s",s); if(s[0]=='C'){ int x,val; scanf("%d%d",&x,&val); if(a[x] != val){ Q[++tot] = Node{i,0,1,a[x],x,0}; Q[++tot] = Node{i,0,2,val,x,0}; a[x] = val; } } if(s[0]=='Q'){ int x,y,k; scanf("%d%d%d",&x,&y,&k); Q[++tot] = Node{i,++cnt,3,k,x,y}; } } for(int i=1;i<=m;i++){ Q[++tot] = Node{m+1,0,1,a[i],i,0}; } sort(Q+1,Q+tot+1,cmp); for(int i=1;i<=tot;i++){ if(Q[i].op==1) Up(Q[i].l,-1); if(Q[i].op==2) Up(Q[i].l,1); if(Q[i].op==3) ans[Q[i].id] = Qu(Q[i].r) - Qu(Q[i].l-1); } for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]); return 0; }