1. 程式人生 > >51nod 1463 找朋友(線段樹+離線處理)

51nod 1463 找朋友(線段樹+離線處理)

query max nbsp update ring tdi 包含 覆蓋 vector

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463

題意:

技術分享

思路:

好題!

先對所有查詢進行離線處理,按照右區間排序,因為k一共最多只有10個,所有在該區間內的B數組,每次枚舉K值,通過這樣的方式來得到另外一個B值。但是這樣得到的B值它在B數組中的位置必須在當前數的左邊。如下圖:(j為當前數在B數組中的位置,pos為計算得到的另一個B值在數組中的位置)

技術分享

這兩個數的和記錄在pos中,這裏pos的位置必須在j的左邊,假設第q個查詢區間如上圖所示(請在腦中將pos和j互換一下),那麽此時j就沒包含在該區間內,這樣一來,查詢得到的值就會有錯。因為我們是按照右區間排序的,所以右區間會不斷擴大,只要左邊被覆蓋的,那麽右邊的數肯定是在該區間內的。

用線段樹維護即可。具體請參見代碼。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11
using namespace std; 12 typedef long long ll; 13 const int INF = 0x3f3f3f3f; 14 const int maxn=1e5+5; 15 16 int n,q,m; 17 int A[maxn],B[maxn],K[15],B_pos[maxn],ans[maxn]; 18 19 struct node 20 { 21 int l,r,id; 22 bool operator<(const node& rhs) const 23 {
24 return r<rhs.r; 25 } 26 }Q[maxn]; 27 28 int MAX[maxn<<2]; 29 int val[maxn<<2]; 30 31 void build(int l, int r, int o) 32 { 33 val[o]=0; 34 if(l==r) return; 35 int mid=(l+r)>>1; 36 build(l,mid,o<<1); 37 build(mid+1,r,o<<1|1); 38 } 39 40 void update(int l, int r, int pos, int x, int o) 41 { 42 val[o]=max(val[o],x); 43 if(l==pos && r==pos) return; 44 int mid=(l+r)>>1; 45 if(pos<=mid) update(l,mid,pos,x,o<<1); 46 else update(mid+1,r,pos,x,o<<1|1); 47 } 48 49 int query(int ql, int qr, int l, int r, int o) 50 { 51 if(ql<=l && qr>=r) return val[o]; 52 int mid=(l+r)>>1; 53 int res=0; 54 if(ql<=mid) res=max(res,query(ql,qr,l,mid,o<<1)); 55 if(qr>mid) res=max(res,query(ql,qr,mid+1,r,o<<1|1)); 56 return res; 57 } 58 59 int main() 60 { 61 //freopen("in.txt","r",stdin); 62 scanf("%d%d%d",&n,&q,&m); 63 for(int i=1;i<=n;i++) scanf("%d",&A[i]); 64 for(int i=1;i<=n;i++) {scanf("%d",&B[i]);B_pos[B[i]]=i;} 65 for(int i=1;i<=m;i++) scanf("%d",&K[i]); 66 for(int i=1;i<=q;i++) 67 { 68 scanf("%d%d",&Q[i].l,&Q[i].r); 69 Q[i].id=i; 70 } 71 sort(Q+1,Q+q+1); 72 build(1,n,1); 73 int s=1; 74 memset(MAX,0,sizeof(MAX)); 75 for(int i=1;i<=q;i++) 76 { 77 int r=Q[i].r; 78 for(int j=s;j<=r;j++) 79 { 80 for(int k=1;k<=m;k++) 81 { 82 int tmp_B=B[j]+K[k]; 83 int pos=B_pos[tmp_B]; //得到tmp_B在B數組中的位置 84 if(tmp_B<=n && pos<j && A[pos]+A[j]>MAX[pos]) 85 { 86 MAX[pos]=A[pos]+A[j]; //此時pos位置的最大值是由pos和[1,j)之間的一個數相加而成 87 update(1,n,pos,MAX[pos],1); //更新線段樹 88 } 89 tmp_B=B[j]-K[k]; 90 pos=B_pos[tmp_B]; 91 if(tmp_B>=1 && pos<j && A[pos]+A[j]>MAX[pos]) 92 { 93 MAX[pos]=A[pos]+A[j]; 94 update(1,n,pos,MAX[pos],1); 95 } 96 } 97 } 98 ans[Q[i].id]=query(Q[i].l,Q[i].r,1,n,1); //查詢該區間內的最大值 99 s=r; 100 } 101 for(int i=1;i<=q;i++) printf("%d\n",ans[i]); 102 return 0; 103 }

51nod 1463 找朋友(線段樹+離線處理)