【解题报告】编程之美复赛 ——猜数字
题目连接:http://hihocoder.com/contest/msbop2015round3/problem/2
大意:给定一个数组,然后有多个查询(l,r,x)求在l~r区间内和x最小的差。
线段树维护。。。离线操作
先假定要求的是区间内比x小的数的最小差。那么我们可以从小到大逐个向线段树里面添加数组的值,然后从小到大查询每个查询的结果。
如:
数组:[1 8 3 4 9 2 7 6 5] 查询:[(1 9 10)、(3 7 9)、(5 6 5)]
逐个向线段树里面添加值。
初始化是0,
逐个添加1,2,3,4,5
变成[1,0,3,4,0,2,0,0,5] 这时候执行查询(5,6,5)。线段树维护的是区间最大值。那么这样查询出的结果就是2。也就是说区间5~6内比5小且最大的数是2。取绝对值就是3了。
离线操作也就是预先读取出全部的查询,按x排序,然后在添加的过程中逐个求出(不是按原来的顺序求),最后再根据输入的顺序输出全部的查询结果。
以同样的方法可以求出比x大且最小的数。取绝对值再和之前的结果求较小值就是题目要求的查询的结果了。
1 /*l~r的节点的左孩子是l~(l+r)/2,右孩子是(l+r)/2+1~r*/ 2 #include<stdio.h> 3 #include<algorithm> 4 using namespace std; 5 #define MAXLEN 1500000 6 typedef int SaveData;/*节点内的储存数据*/ 7 typedef int Point;/*端点下标*/ 8 typedef struct node 9 { 10 Point l,r;/*左右端点*/ 11 SaveData value;/*值,如保存和,最值等等*/ 12 /*struct node *pl,*pr; /*链式情况下左右节点指标*/ 13 }SeTree; 14 SeTree tree[MAXLEN]={0}; 15 SaveData ans;/*返回查询结果*/ 16 /*初始化线段树*/ 17 void bulid(Point v,Point l,Point r) 18 { 19 tree[v].l=l; 20 tree[v].r=r; 21 if(l==r) 22 { 23 tree[v].value=-999999999; 24 //scanf("%ld",&tree[v].value); 25 return ; 26 } 27 Point mid=(l+r)/2; 28 bulid(v*2,l,mid); 29 bulid(v*2+1,mid+1,r); 30 tree[v].value=max(tree[v*2].value,tree[v*2+1].value); 31 } 32 /*更新区间l~r = m*/ 33 SaveData update(Point v,Point l,Point r,SaveData m) 34 { 35 SaveData s; 36 if(tree[v].l==l&&tree[v].r==r) 37 { 38 tree[v].value=m; 39 return m; 40 } 41 int mid=(tree[v].l+tree[v].r)/2; 42 if(r<=mid) {s=update(v*2,l,r,m);} 43 else 44 { 45 if(l>mid) update(v*2+1,l,r,m); 46 else 47 { 48 update(v*2,l,mid,m); 49 update(v*2+1,mid+1,r,m); 50 } 51 } 52 tree[v].value=max(tree[v*2].value,tree[v*2+1].value); 53 return s; 54 } 55 /*查询l~r*/ 56 void query(Point v,Point l,Point r) 57 { 58 if(tree[v].l==l&&tree[v].r==r) 59 { 60 ans=max(tree[v].value,ans);/*ans为全局变量*/ 61 return ; 62 } 63 int mid=(tree[v].l+tree[v].r)/2; 64 if(r<=mid)query(v*2,l,r); 65 else 66 { 67 if(l>mid) query(v*2+1,l,r); 68 else 69 { 70 query(v*2,l,mid); 71 query(v*2+1,mid+1,r); 72 } 73 } 74 } 75 pair<int,int> sc[200005]; 76 pair<int,pair<pair<int,int>,int> > q[200005]; 77 int ansans[200005]; 78 int t,n,qnum,i,j; 79 const int INF=1000000000; 80 int go() 81 { 82 bulid(1,1,n); 83 i=n-1;j=qnum-1; 84 while(i>=-1&&j>=0) 85 { 86 if(i>=0&&sc[i].first>=q[j].first) 87 { 88 //printf("up:%d %d\n",sc[i].second,-sc[i].first); 89 update(1,sc[i].second,sc[i].second,INF-sc[i].first); 90 i--; 91 } 92 else 93 { 94 ans=-9999999999; 95 //printf("qu:%d %d\n",q[j].second.first.first,q[j].second.first.second); 96 query(1,q[j].second.first.first,q[j].second.first.second); 97 ansans[q[j].second.second]=min(ansans[q[j].second.second],(INF-ans)-q[j].first); 98 j--; 99 } 100 } 101 } 102 int main() 103 { 104 int cas=1; 105 scanf("%d",&t); 106 while(t--) 107 { 108 scanf("%d%d",&n,&qnum); 109 bulid(1,1,n); 110 for(i=0;i<n;i++) 111 { 112 scanf("%d",&sc[i].first); 113 sc[i].second=i+1; 114 } 115 sort(sc,sc+n); 116 for(i=0;i<qnum;i++) 117 { 118 int l,r; 119 scanf("%d%d%d",&l,&r,&q[i].first); 120 if(l<=0) l=1; 121 if(r>n) r=n; 122 q[i].second.first.first=l; 123 q[i].second.first.second=r; 124 q[i].second.second=i; 125 } 126 sort(q,q+qnum); 127 i=0;j=0; 128 while(i<=n&&j<qnum) 129 { 130 if(i<n&&sc[i].first<=q[j].first) 131 { 132 //printf("up:%d %d\n",sc[i].second,sc[i].first); 133 update(1,sc[i].second,sc[i].second,sc[i].first); 134 i++; 135 } 136 else 137 { 138 ans=-9999999999; 139 //printf("qu:%d %d\n",q[j].second.first.first,q[j].second.first.second); 140 query(1,q[j].second.first.first,q[j].second.first.second); 141 ansans[q[j].second.second]=q[j].first-ans; 142 j++; 143 } 144 } 145 go(); 146 printf("Case #%d:\n",cas++); 147 for(i=0;i<qnum;i++) 148 { 149 printf("%d\n",ansans[i]); 150 } 151 } 152 return 0; 153 }