[51nod] 1463 找朋友 #离线+扫描线
给定:
两个长度为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 }
转载请注明出处 -- 如有意见欢迎评论