[51nod] 1463 找朋友 #离线+扫描线

1463 找朋友

基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 难度:5级算法题
 
给定:
两个长度为n的数列A 、B
一个有m个元素的集合K
询问Q次
每次询问[l,r],输出区间内满足|Bi-Bj|∈K 的最大Ai+Aj
 
数据约定:
n,Q<=100000
m <= 10
0<=A[i]<=1000000000
1<=B[i]<=n
1<=K[i]<=n
保证B[i]互不相等
Input
n Q m
A1 A2 ....An
B1 B2 ....Bn
K1 K2 ....Km
l1 r1
l2 r2
.
.
lQ rQ
Output
Q行,每行一个整数表示相对应的答案。
如果找不到这样的两个数则输出0。
Input示例
4 2 2
1 2 3 4
3 2 1 4
1 3
1 4
2 3
Output示例
7
5
Analysis分析
正解:扫描线 + 离线
首先将询问区间按右端点进行升序排序
然后从 1 扫到 n 扫过每一个元素
假定当前元素为 i 
枚举 K 集合,找出所有在 i 左边的并且与 i 满足条件的另一个元素 j
(我们可以通过 K 和 i 逆推出 j 的 Bi 即排名,然后各种简单操作可以找到 j 的编号位置)
然后将这两个元素的和储存在 j 中(当然是取最大值更新啦)
那么这么干有一个缺点:如果 i 右边有另一个更优的元素,那么储存在 j 中的答案会被更新,不一定可以满足某些询问区间
所以随扫随答,如果当前这个 i 挂着询问(我把询问直接用链表在右端点上qwq),那么当即查询 [ Li,Ri ] 的答案的最大值(这里可用数据结构如线段树优化)
如此这般便不会被后面的元素影响了

所以我还学到一件事情,如果有区间相关的话,试图排序并逐步扩大统计范围以确定当前答案为可行解
 
Code代码
 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define mid (L+R)/2
 5 #define lc (rt << 1)
 6 #define rc (rt<<1|1)
 7 #define maxn 1000000
 8 using namespace std;
 9 
10 int arr[maxn],brr[maxn],cnt,bos[maxn],sto[maxn],k[maxn],n,m,q;
11 
12 struct node{
13     int maxx;
14 }T[maxn*4];
15 
16 void build(int rt,int L,int R){
17     if(L == R) T[rt].maxx = arr[L];
18     else{
19         build(lc,L,mid); build(rc,mid+1,R);
20         T[rt].maxx = max(T[lc].maxx,T[rc].maxx);
21     }
22 }
23 
24 void modify(int rt,int L,int R,int pos,int val){
25     if(L == R) T[rt].maxx = val,sto[pos] = val;
26     else{
27         if(pos > R || pos < 1) return;
28         if(pos <= mid) modify(lc,L,mid,pos,val);
29         else modify(rc,mid+1,R,pos,val);
30         T[rt].maxx = max(T[lc].maxx,T[rc].maxx);
31     }
32 }
33 
34 int query(int rt,int L,int R,int qL,int qR){
35     if(qL <= L && R <= qR) return T[rt].maxx;
36     else{
37         int ans = 0;
38         if(qL <= mid) ans = max(ans,query(lc,L,mid,qL,qR));
39         if(qR > mid) ans = max(ans,query(rc,mid+1,R,qL,qR));
40         return ans;
41     }
42 }
43 
44 struct ask{
45     int from,L,R,ans,ord; // first[R]
46 }e[maxn];
47 int tot,first[maxn];
48 void insert(int L,int R,int ord){
49     tot++;
50     e[tot].ord = ord,
51     e[tot].L = L,
52     e[tot].R = R,
53     e[tot].from = first[R];
54     first[R] = tot;
55 }
56 
57 bool cmp(const ask &A,const ask &B){ return A.ord < B.ord; }
58 
59 int main(){
60     scanf("%d%d%d",&n,&q,&m);
61     
62     for(int i = 1;i <= n;i++) scanf("%d",&arr[i]);
63     for(int i = 1;i <= n;i++) scanf("%d",&brr[i]),bos[brr[i]] = i;
64     for(int i = 1;i <= m;i++) scanf("%d",&k[i]);
65     
66     for(int i = 1;i <= q;i++){
67         int L,R;
68         scanf("%d%d",&L,&R);
69         insert(L,R,i);
70     }
71     
72 //    printf("#bos: "); for(int i = 1;i <= n;i++) printf("%d ",bos[i]); cout << endl;
73     
74     for(int i = 2;i <= n;i++){
75         for(int j = 1;j <= m;j++){
76             int ppos = bos[brr[i]-k[j]]; //printf("~#%d: ppos %d i-k[j] %d\n",brr[i],ppos,i-k[j]);
77             if(ppos >= 1 && ppos < i && sto[ppos] < arr[ppos]+arr[i])
78                 modify(1,1,n,ppos,arr[ppos]+arr[i]);
79             ppos = bos[brr[i]+k[j]]; //printf("~#%d: ppos %d i-k[j] %d\n",brr[i],ppos,i-k[j]);
80             if(ppos >= 1 && ppos < i && sto[ppos] < arr[ppos]+arr[i])
81                 modify(1,1,n,ppos,arr[ppos]+arr[i]);
82         }for(int p = first[i];p;p = e[p].from){
83             e[p].ans = query(1,1,n,e[p].L,e[p].R);
84         }//printf("#%d: ",i); for(int j = 1;j <= n;j++) printf("%d ",sto[j]); cout << endl;
85     }sort(e+1,e+1+tot,cmp);
86     
87     for(int i = 1;i <= tot;i++) printf("%d\n",e[i].ans);
88     
89     return 0;
90 }
qwq注释代码多又多

 

posted @ 2017-10-30 16:53  Leviaton  阅读(312)  评论(0编辑  收藏  举报