#include<stdio.h> #include<algorithm> using namespace std; #define MY_MIN 99999999 #define MY_MAX -99999999 #pragma comment(linker,"/STACk:1024000000,1024000000") struct CNode { int L,R; int nMin,nMax; CNode *pLeft,*pRight; }; int nMax,nMin; CNode Tree[1000000]; int nCount=0; void BuildTree(CNode *pRoot,int L,int R) { pRoot->L=L; pRoot->R=R; pRoot->nMin=MY_MIN; pRoot->nMax=MY_MAX; if(L!=R) { nCount++; pRoot->pLeft=Tree+nCount; nCount++; pRoot->pRight=Tree+nCount; BuildTree(pRoot->pLeft,L,(R+L)/2); BuildTree(pRoot->pRight,(R+L)/2+1,R); } } void Insert(CNode *pRoot,int i,int v) { if(pRoot->L==i&&pRoot->R==i) { pRoot->nMin=pRoot->nMax=v; return ; } pRoot->nMin=min(pRoot->nMin,v); pRoot->nMax=max(pRoot->nMax,v); if(i<=(pRoot->L+pRoot->R)/2) Insert(pRoot->pLeft,i,v); else Insert(pRoot->pRight,i,v); } void Query(CNode *pRoot,int s,int e) { if(pRoot->nMin>=nMin&&pRoot->nMax<=nMax) return ; if(s==pRoot->L&&e==pRoot->R) { nMin=min(pRoot->nMin,nMin); nMax=max(pRoot->nMax,nMax); return ; } if(e<=(pRoot->L+pRoot->R)/2) Query(pRoot->pLeft,s,e); else if(s>=(pRoot->R+pRoot->L)/2+1) Query(pRoot->pRight,s,e); else { Query(pRoot->pLeft,s,(pRoot->L+pRoot->R)/2); Query(pRoot->pRight,(pRoot->L+pRoot->R)/2+1,e); } } int main() { int n,q,h; int i,j,k; scanf("%d%d",&n,&q); BuildTree(Tree,1,n); for(i=1;i<=n;i++) { scanf("%d",&h); Insert(Tree,i,h); } for(i=0;i<q;i++) { int s,e; scanf("%d%d",&s,&e); nMax=MY_MAX; nMin=MY_MIN; Query(Tree,s,e); printf("%d ",nMax-nMin); } return 0; }
用线段树解题,关键是要想清楚每个节点要存哪些信息
(当然区间起终点,以及左右子节点指针是必须的),
以及这些信息如何高效更新,维护,查询。不要一更新
就更新到叶子节点,那样更新效率最坏就可能变成O(n)
的了。
先建树,然后插入数据,然后更新,查询。