分析問題並考慮已知的數據結構。
細節處理很重要。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; //用標記數組的話果然不對 比如樣例3 1 2 5 4,走一遍之後,再從頭開始進行遍歷的話,3+1,3-1都有標記,後面的都加了1 //還有得注意到底是什麼情況下用sum(a)-sum(b);什麼情況下只用sum(a)就夠了 //樹狀數組更新之後 其後所有的數都會更新 切記 int a[100005]; int visit[100005]; int c[100005]; int ret[100005]; int num[100005]; struct vv { int l,r; int id; }v[100005]; int max(int a,int b) { if(a<b) return b; else return a; } int min(int a,int b) { if(a<b) return a; else return b; } int cmp(struct vv x,struct vv y) { return x.l<y.l; } int lowbit(int x) { return x&-x; } void update(int a,int b) { for(int i=a;i<=100005;i+=lowbit(i)) c[i]+=b; } int sum(int a) { int ret=0; for(int i=a;i>=1;i-=lowbit(i)) ret+=c[i]; return ret; } int main() { int case_num; scanf("%d",&case_num); while(case_num--) { memset(c,0,sizeof(c)); memset(num,0,sizeof(num)); int n,m; scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); num[a[i]]=i; } num[0] = n+10; num[n+1] = n+10; for(int i = 1;i <= n;i++) { if(i < num[a[i]-1] && i < num[a[i]+1]) //d段數加1 update(i,1); else if(i > num[a[i]-1] && i > num[a[i]+1]) //段數減1 update(i,-1); } for(int i=0;i<m;i++) { scanf("%d%d",&v[i].l,&v[i].r); v[i].id=i;//利用這個Id進行編號是個好技巧...應該可以這麼輸出? } sort(v,v+m,cmp); int i = 1; int j = 0; while(j < m) //m次詢問 { while(i <= n && i < v[j].l) //從左到右刪除 { if(i > num[a[i]-1] && i > num[a[i]+1]) //刪除a[i],則把原來加的一,減去 update(i,-1); else if(i < num[a[i]-1] && i < num[a[i]+1]) { int Min = min(num[a[i]-1],num[a[i]+1]); int Max = max(num[a[i]-1],num[a[i]+1]); update(i,-1); //願來加的一減去 update(Min,1); //少了a[i],則相應段數增加 update(Max,1); // . ... } else if(i < num[a[i]-1]) { update(i,-1); update(num[a[i]-1],1); } else { update(i,-1); update(num[a[i]+1],1); } i++; } ret[v[j].id]= sum(v[j].r); //保存答案 j++; } for(int i=0;i<m;i++) printf("%d\n",ret[i]); } return 0; } #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; //用標記數組的話果然不對 比如樣例3 1 2 5 4,走一遍之後,再從頭開始進行遍歷的話,3+1,3-1都有標記,後面的都加了1 //還有得注意到底是什麼情況下用sum(a)-sum(b);什麼情況下只用sum(a)就夠了 //樹狀數組更新之後 其後所有的數都會更新 切記 int a[100005]; int visit[100005]; int c[100005]; int ret[100005]; int num[100005]; struct vv { int l,r; int id; }v[100005]; int max(int a,int b) { if(a<b) return b; else return a; } int min(int a,int b) { if(a<b) return a; else return b; } int cmp(struct vv x,struct vv y) { return x.l<y.l; } int lowbit(int x) { return x&-x; } void update(int a,int b) { for(int i=a;i<=100005;i+=lowbit(i)) c[i]+=b; } int sum(int a) { int ret=0; for(int i=a;i>=1;i-=lowbit(i)) ret+=c[i]; return ret; } int main() { int case_num; scanf("%d",&case_num); while(case_num--) { memset(c,0,sizeof(c)); memset(num,0,sizeof(num)); int n,m; scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); num[a[i]]=i; } num[0] = n+10; num[n+1] = n+10; for(int i = 1;i <= n;i++) { if(i < num[a[i]-1] && i < num[a[i]+1]) //d段數加1 update(i,1); else if(i > num[a[i]-1] && i > num[a[i]+1]) //段數減1 update(i,-1); } for(int i=0;i<m;i++) { scanf("%d%d",&v[i].l,&v[i].r); v[i].id=i;//利用這個Id進行編號是個好技巧...應該可以這麼輸出? } sort(v,v+m,cmp); int i = 1; int j = 0; while(j < m) //m次詢問 { while(i <= n && i < v[j].l) //從左到右刪除 { if(i > num[a[i]-1] && i > num[a[i]+1]) //刪除a[i],則把原來加的一,減去 update(i,-1); else if(i < num[a[i]-1] && i < num[a[i]+1]) { int Min = min(num[a[i]-1],num[a[i]+1]); int Max = max(num[a[i]-1],num[a[i]+1]); update(i,-1); //願來加的一減去 update(Min,1); //少了a[i],則相應段數增加 update(Max,1); // . ... } else if(i < num[a[i]-1]) { update(i,-1); update(num[a[i]-1],1); } else { update(i,-1); update(num[a[i]+1],1); } i++; } ret[v[j].id]= sum(v[j].r); //保存答案 j++; } for(int i=0;i<m;i++) printf("%d\n",ret[i]); } return 0; }