Minimum Sum
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3047 Accepted Submission(s): 701
Problem Description
You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you some intervals [l, r]. For each interval, you need to find a number x to make as small as possible!
Input
The first line is an integer T (T <= 10), indicating the number of test cases. For each test case, an integer N (1 <= N <= 100,000) comes first. Then comes N positive integers x (1 <= x <= 1,000, 000,000) in the next line. Finally, comes an integer Q (1 <= Q <= 100,000), indicting there are Q queries. Each query consists of two integers l, r (0 <= l <= r < N), meaning the interval you should deal with.
Output
For the k-th test case, first output “Case #k:” in a separate line. Then output Q lines, each line is the minimum value of . Output a blank line after every test case.
Sample Input
2
5
3 6 2 2 4
2
1 4
0 2
2
7 7
2
0 1
1 1
Sample Output
Case #1:
6
4
Case #2:
0
0
区间第k大的题目一般两种做法,,划分树 主席树,不过貌似划分树只支持静态区间第k大。
这道题由于内存限制 只能用划分树。。具体就是 先找出区间[l,r]内的中位数,(为什么是中位数,大白书貌似有介绍),然后直接求和。
MLE到死啊,,注释memset部分之后就过了,不知道为什么
划分树代码:
1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack> 7 #include <cstdio> 8 #include <string> 9 #include <vector> 10 #include <cstdlib> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 typedef unsigned long long ull; 16 typedef long long ll; 17 const int inf = 0x3f3f3f3f; 18 const double eps = 1e-8; 19 const int maxn = 100010; 20 int sorted[maxn],tree[20][maxn],toleft[20][maxn]; //toleft[dep][i]表示第dep层1-i中进入左子树元素的个数 21 ll leftsum[20][maxn], sum[maxn]; //leftsum[dep][i]表示第dep层1-i中进入左子树元素的和 22 23 void build (int l,int r,int dep) 24 { 25 if (l == r) 26 return; 27 int mid = (l + r) >> 1; 28 int same = mid - l + 1; 29 for (int i = l; i <= r; i++) 30 if (tree[dep][i] < sorted[mid]) 31 same--; 32 int lpos = l,rpos = mid + 1; 33 for (int i = l; i <= r; i++) 34 { 35 if (tree[dep][i] < sorted[mid]) 36 { 37 tree[dep+1][lpos++] = tree[dep][i]; 38 leftsum[dep][i] = leftsum[dep][i-1] + tree[dep][i]; 39 } 40 else if (tree[dep][i] == sorted[mid] && same > 0) 41 { 42 tree[dep+1][lpos++] = tree[dep][i]; 43 leftsum[dep][i] = leftsum[dep][i-1] + tree[dep][i]; 44 same--; 45 } 46 else 47 { 48 tree[dep+1][rpos++] = tree[dep][i]; 49 leftsum[dep][i] = leftsum[dep][i-1]; 50 } 51 toleft[dep][i] = toleft[dep][l-1] + lpos - l; 52 } 53 build (l,mid,dep+1); 54 build (mid+1,r,dep+1); 55 } 56 int lnum,rnum; 57 ll lsum,rsum; 58 int query(int l,int r,int dep,int ua,int ub,int k) 59 { 60 if (ua == ub) 61 return tree[dep][ua]; 62 int mid = (l + r) >> 1; 63 int cnt = toleft[dep][ub] - toleft[dep][ua-1]; 64 if (cnt >= k) 65 { 66 int newl = l + toleft[dep][ua-1] - toleft[dep][l-1]; 67 int newr = newl + cnt - 1; 68 return query(l,mid,dep+1,newl,newr,k); 69 } 70 else 71 { 72 int newr = ub + toleft[dep][r] - toleft[dep][ub]; 73 int newl = newr - (ub - ua - cnt); 74 lnum += cnt; 75 lsum += leftsum[dep][ub] - leftsum[dep][ua-1]; 76 return query(mid+1,r,dep+1,newl,newr,k-cnt); 77 } 78 } 79 80 int main(void) 81 { 82 #ifndef ONLINE_JUDGE 83 freopen("in.txt","r",stdin); 84 #endif 85 int T, cas = 1; 86 scanf ("%d",&T); 87 while (T--) 88 { 89 int n,m; 90 scanf ("%d",&n); 91 sum[0] = 0; 92 for (int i = 1; i <= n; i++) 93 { 94 scanf ("%d",&tree[0][i]); 95 sum[i] = sum[i-1] + tree[0][i]; 96 sorted[i] = tree[0][i]; 97 } 98 sort(sorted+1,sorted+n+1); 99 build (1,n,0); 100 scanf ("%d",&m); 101 printf ("Case #%d: ",cas++); 102 while (m--) 103 { 104 int u, v; 105 scanf ("%d%d",&u,&v); 106 u++,v++; 107 lnum = 0; 108 lsum = 0; 109 int mid_num = query(1,n,0,u,v,(v-u)/2+1); //中位数 110 rnum = (v - u + 1 - lnum); // u~v 区间内大于mid_num的个数 111 rsum = (sum[v] - sum[u-1] - lsum); //u~v 区间内大于mid_num的数的和 112 ll ans = rsum - lsum + mid_num * (lnum - rnum); 113 printf("%I64d ",ans); 114 } 115 printf(" "); 116 } 117 return 0; 118 }
主席树部分代码:(主席树会MLE,已经和划分树代码对拍过,应该没问题)
1 typedef long long ll; 2 const int maxn = 1e5+10; 3 int n,q,tot; 4 5 //主席树部分 6 int lson[maxn*20],rson[maxn*20],c[maxn*20],tree[maxn]; 7 8 ll sum[maxn*20]; 9 int build (int l,int r) 10 { 11 int root = tot++; 12 c[root] = 0; 13 sum[root] = 0; 14 if (l != r) 15 { 16 int mid = (l + r) >> 1; 17 lson[root] = build(l,mid); 18 rson[root] = build(mid+1,r); 19 } 20 return root; 21 } 22 int update(int root,int pos,int val,int k) 23 { 24 int newroot = tot++; 25 int tmp = newroot; 26 int l = 1, r = n; 27 c[newroot] = c[root] + val; 28 sum[newroot] = sum[root] + k; 29 while (l < r) 30 { 31 int mid = (l + r) >> 1; 32 if (pos <= mid) 33 { 34 rson[newroot] = rson[root]; 35 root = lson[root]; 36 lson[newroot] = tot++; 37 newroot = lson[newroot]; 38 r = mid; 39 } 40 else 41 { 42 lson[newroot] = lson[root]; 43 root = rson[root]; 44 rson[newroot] = tot++; 45 newroot = rson[newroot]; 46 l = mid + 1; 47 } 48 c[newroot] = c[root] + val; 49 sum[newroot] = sum[root] + k; 50 } 51 return tmp; 52 } 53 ll lsum,rsum; //lsum小于中位数的和,rsum大于中位数的和 54 ll query(int root,int l,int r,int ua,int ub) //查询1-root 大于ua小于ub的和 55 { 56 if (ub < ua) 57 return 0; 58 if (ua <= l && ub >= r) 59 { 60 return sum[root]; 61 } 62 int mid = (l + r) >> 1; 63 ll t1 = 0,t2 = 0; 64 if (ua <= mid) 65 t1 = query(lson[root],l,mid,ua,ub); 66 if (ub > mid) 67 t2 = query(rson[root],mid+1,r,ua,ub); 68 return t1 + t2; 69 } 70 int query1(int root,int l,int r,int ua,int ub) //查询1-root 在ua ub 之间的数的个数 71 { 72 if (ub < ua) 73 return 0; 74 if (ua <= l && ub >= r) 75 { 76 return c[root]; 77 } 78 int mid = (l + r) >> 1; 79 int t1 = 0,t2 = 0; 80 if (ua <= mid) 81 t1 = query1(lson[root],l,mid,ua,ub); 82 if (ub > mid) 83 t2 = query1(rson[root],mid+1,r,ua,ub); 84 return t1 + t2; 85 } 86 int query(int left,int right,int k) //查询left right区间第k大 87 { 88 int l_root = tree[left-1]; 89 int r_root = tree[right]; 90 int l = 1, r = n; 91 while (l < r) 92 { 93 int mid = (l + r) >> 1; 94 int tmp = c[lson[r_root]] - c[lson[l_root]]; 95 if (tmp <= k) 96 { 97 k -= tmp; 98 r_root = rson[r_root]; 99 l_root = rson[l_root]; 100 l = mid + 1; 101 } 102 else 103 { 104 l_root = lson[l_root]; 105 r_root = lson[r_root]; 106 r = mid; 107 } 108 } 109 return l; 110 } 111 int vec[maxn],rel[maxn],idx; 112 //离散化 113 inline void init_hash() 114 { 115 sort(vec,vec+idx); 116 idx = unique(vec,vec+idx) - vec; 117 } 118 inline int _hash(ll x) 119 { 120 return lower_bound(vec,vec+idx,x) - vec + 1; 121 } 122 123 124 int main(void) 125 { 126 #ifndef ONLINE_JUDGE 127 freopen("in.txt","r",stdin); 128 freopen("wa.txt","w",stdout); 129 #endif 130 int t,cas = 1; 131 scanf ("%d",&t); 132 while (t--) 133 { 134 memset(sum,0,sizeof(sum)); 135 scanf ("%d",&n); 136 idx = tot = 0; 137 for (int i = 1; i<= n; i++) 138 { 139 //scanf ("%d",a+i); 140 scanf ("%d",tree+i); 141 vec[idx++] = tree[i]; 142 } 143 init_hash(); 144 tree[0] = build(1,n); 145 for (int i = 1; i <= n; i++) 146 { 147 int tmp = _hash(tree[i]); 148 rel[tmp] = tree[i]; 149 150 tree[i] = update(tree[i-1],tmp,1,tree[i]); 151 //tree[i] = tmp2; 152 } 153 scanf ("%d",&q); 154 printf("Case #%d: ",cas++); 155 while (q--) 156 { 157 int u,v; 158 scanf ("%d%d",&u,&v); 159 u++,v++; 160 int vir_mid = query(u,v,(v-u)/2); 161 int mid_num = rel[vir_mid]; //中位数 162 lsum = query(tree[u-1],1,n,1,vir_mid-1); 163 rsum = query(tree[u-1],1,n,vir_mid+1,n); 164 ll x1 = lsum, x2 = rsum; 165 166 lsum = query(tree[v],1,n,1,vir_mid-1); 167 rsum = query(tree[v],1,n,vir_mid+1,n); 168 int lnum = query1(tree[v],1,n,1,vir_mid - 1) - query1(tree[u-1],1,n,1,vir_mid - 1); 169 int rnum = query1(tree[v],1,n,vir_mid + 1,n) - query1(tree[u-1],1,n,vir_mid + 1,n); 170 printf("%I64d ",rsum - x2 - (lsum - x1) + (lnum - rnum) * mid_num); 171 } 172 printf(" "); 173 } 174 return 0; 175 176 }