題目
前幾篇文章中出現了“靠”等字眼,一次偶然的機會百度到了一篇轉載自我的文章,轉載者將問中的包含“情緒”的語句全部刪掉了,我這才注意到,最近我變得很容易情緒不好!!我錯了,我想起了高中一老師說的“心靜如水,激情似火”!看來我需要修鍊的東西還很多啊……
題目大意:給定10^5的一個數組,(10^5次)查詢給定區間中出現次數和這個數的值相同的數的個數
例如:
7 23 1 2 2 3 3 71 73 4
7個數2個詢問1-7中1出現1次、2出現2次、3出現3次,所以答案為3。3-4中只有2出現2次,所以答案為1
代碼寫的有點挫,因為調試了好久。首先給定數組後,可以成為答案的數字不會超過500個(1+2*2+3*3+……500*500 > 10^5)
其次,離線處理也是比較常見的!由於x出現恰好是x次,所以需要將向左第x個標記為1,向左第x+1個就要標記為-1,其餘標記為0,這樣就可以有效查詢區間中恰好出現x次的數字個數(區間求和)
/**離線線段樹問題*/#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <map>#include <queue>using namespace std;#define N 100010int ai[N],_ai[N],re[N];struct note{ int l,r,index;}query[N];bool q_cmp(const note a,const note b){ return a.r < b.r ||(a.r == b.r && a.l < b.l);}int num[N];///線段樹#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define fmid int m = (l+r)>>1;int sum[N*4];void init(){ memset(sum,0,sizeof(sum));}void push_up(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1];}int f_query(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) { return sum[rt]; } fmid; int re = 0; if(L <= m) re += f_query(L,R,lson); if(m < R) re += f_query(L,R,rson); return re;}void update(int pos,int val,int l,int r,int rt){ if(pos == 0) return; if(l == r) { sum[rt] = val; return; } fmid; if(pos <= m) update(pos,val,lson); else update(pos,val,rson); push_up(rt);}///PPPPPPPPPPPPPPPPPPPPPvoid _update(int pos,int val,int l,int r,int rt){ //cout << pos << " " << val << "\n"; update(pos,val,l,r,rt);}int main(){ int n,m; while(cin >> n >> m) { for(int i = 1;i <= n;i++) scanf("%d",&ai[i]); for(int i = 0;i < m;i++) scanf("%d%d",&query[i].l,&query[i].r); for(int i = 0;i < m;i++) query[i].index = i; sort(query,query+m,q_cmp); for(int i = 1;i <= n;i++) _ai[i] = ai[i]; sort(_ai+1,_ai+n+1); memset(num,0,sizeof(num)); num[1] = 1; int kk = 1; for(int i = 2;i <= n;i++) { if(_ai[i] == _ai[i-1]) num[kk]++; else { _ai[++kk] = _ai[i]; num[kk] = 1; } } int k = 1; for(int i = 1;i <= kk;i++) { if(num[i] >= _ai[i]) _ai[k++] = _ai[i]; } map <int ,int> mymap; kk = 1; for(int i = 1;i < k;i++) { mymap[ _ai[i] ] = kk++; } //for(int i = 1;i < k;i++) cout << _ai[i] << " ";cout << kk << " ppp\n"; kk = 0; init(); queue < int > my_queue[500]; int t_pos[500]; memset(t_pos,0,sizeof(t_pos)); for(int i = 1;i <= n;i++) { int t = mymap[ ai[i] ]; if(t != 0) { my_queue[t].push(i); int size = my_queue[t].size() ; if(size == ai[i]) _update(my_queue[t].front(),1,1,n,1);//第一出出現ai[i]次 if(size == ai[i]+1) { _update(t_pos[t],0,1,n,1);//注意將-1左側的改為0 t_pos[t] = my_queue[t].front();//記錄標記為-1的點,已備以後改為0 _update(my_queue[t].front(),-1,1,n,1);//修改為-1 my_queue[t].pop(); _update(my_queue[t].front(),1,1,n,1);//將左側底ai[i]個ao[i]標記為1 } } while(kk < m && query[kk].r == i) { re[query[kk].index] = f_query(query[kk].l,query[kk].r,1,n,1);//查詢該區間的值得情況 kk++; } } for(int i = 0;i < m;i++) cout << re[i] << "\n"; } return 0;}
奇怪,這個代碼居然又wa在了第33組範例,已近過了的題目原來還是可以再錯的啊!!!囧,我抽空看看怎麼回事!!