離散化+線段樹+二分查找

牛客 Forsaken的三維數點

題目描述 

        Forsaken現在在一個三維空間中,空間中每個點都可以用(x,y,z)(x,y,z)表示。突然,三維空間的主人出現了,如果Forsaken想要繼續在三維空間中呆下去,他就必須回答三維空間主人的問題。
        主人會在空間中座標爲(x,y,z)(x,y,z)處加一點能量值,當他加了一定的次數之後,他會問Forsaken一個問題:如果座標(0,0,0)(0,0,0)爲球心,那麼至少需要多大的半徑才能使得球內的能量值總和大於或者等於kk,在這裏,半徑爲00也是可以的。這對於Forsaken來說實在是太難了,因此他把這個問題交給了你。

輸入描述:

第一行一個nn表示操作的次數。
接下來每行首先一個整數opop表示操作的種類。
如果op = 1op=1,接下來33個整數x,y,zx,y,z表示能量值增加的座標。
如果op =2op=2,接下來一個整數kk表示要求的能量值總和。

輸出描述:

對於每個op=2op=2的操作,輸出一個整數表示球的半徑。(數據保證至少有一個22操作)
如果沒有滿足答案的半徑,輸出-11。
示例1

輸入

複製
2
1 1 1 1
2 1

輸出

複製
2

備註:

1 n2e5
1 op2
-1e5 x,y,z1e5
0k2e5
 
首先降維,因爲題目問題的關鍵是舉例,所以通過sqrt(x^2 + y ^2 + z ^2)降爲一維。
 
解法一:離散化+線段樹+二分查找
 
題目座標最大是1e5,平方後是1e10,直接建樹無法實現。但是觀察數據發現,最多有1e5個輸入,也就是說每次做多有1e5個點,因此想到離散化。
離散化的前提是知道全部的輸入,所以想到把問題離線處理。
這樣,把所有的距離輸入後,從小到大排一遍序,便離散處理完了。
 
如何建樹?
線段樹中每一箇中間節點存儲的是它左右孩子節點的能量值的和。
更新操作時,只更新對應的點。
 
對於題目問題的查詢操作:
每一個節點可以分爲兩部分,前半部分 和 後半部分。
假設查詢操作的值爲k,
如果k大於結點的值,則直接返回-1.
如果k小於等於前半部分的能量值,則進入前半部分繼續查找k。否則,進入後半部分查詢 k - sum[i << 1] 。
 
AC代碼:
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <math.h>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <map>
  8 #include <stack>
  9 #include <deque>
 10 #include <iostream>
 11 using namespace std;
 12 typedef long long LL;
 13 const LL N = 200009;
 14   
 15 struct con
 16 {
 17     LL l, r;
 18 } con[4 * N];
 19 LL sum[4 * N];
 20   
 21 LL tri[200009];
 22 LL distill[200009];
 23 struct q
 24 {
 25     LL k;
 26     LL i;
 27 } q[200009];
 28   
 29 map<LL, LL> qq;
 30   
 31 void pushUp(LL i)
 32 {
 33     sum[i] = sum[i << 1] + sum[i << 1 | 1];
 34 }
 35   
 36 void build(LL i, LL l, LL r)
 37 {
 38     con[i].l = l;
 39     con[i].r = r;
 40     if (con[i].l == con[i].r)
 41     {
 42         sum[i] = 0;
 43         return;
 44     }
 45     LL mid = (con[i].l + con[i].r) >> 1;
 46     build(i << 1, l, mid);
 47     build(i << 1 | 1, mid + 1, r);
 48   
 49     pushUp(i);
 50 }
 51   
 52 void update(LL i, LL l, LL r)
 53 {
 54    // cout << " ** " << i << " " << con[i].l << " " << con[i].r << "  " << l << " " << r << endl;
 55     if (con[i].l == l && con[i].r == r)
 56     {
 57         sum[i]++;
 58         return;
 59     }
 60     LL mid = (con[i].l + con[i].r) >> 1;
 61   
 62     if (l > mid)
 63     {
 64         update(i << 1 | 1, l, r);
 65     }
 66     else if (r <= mid)
 67     {
 68         update(i << 1, l, r);
 69     }
 70     else
 71     {
 72         update(i << 1, l, mid);
 73         update(i << 1 | 1, mid + 1, r);
 74     }
 75   
 76     pushUp(i);
 77 }
 78   
 79 LL query(LL i, LL k)
 80 {
 81     //cout << " ?? " << i << " " << con[i].l << " " << con[i].r << " " << sum[i] << "   " << k << endl;
 82     if (sum[i] < k)
 83     {
 84         return -1;
 85     }
 86   
 87     if (con[i].l == con[i].r)
 88     {
 89         return con[i].l;
 90     }
 91   
 92     if (k <= sum[i << 1])
 93     {
 94         return query(i << 1, k);
 95     }
 96     else
 97     {
 98         return query(i << 1 | 1, k - sum[i << 1]);
 99     }
100 }
101   
102 LL dis(LL x, LL y, LL z)
103 {
104     return x * x + y * y + z * z;
105 }
106   
107 int main()
108 {
109     LL n, i, j, m, mid, tmp;
110     LL k, x, y, z, cnt1 = 0, cnt2 = 0, cnt3 = 0;
111   
112     scanf("%lld", &n);
113     for (i = 1; i <= n; i++)
114     {
115         scanf("%lld", &m);
116         if (m == 1)
117         {
118             scanf("%lld%lld%lld", &x, &y, &z);
119             mid = dis(x, y, z);
120             if (qq[mid] == 0)
121             {
122                 distill[++cnt3] = mid;
123                 qq[mid] = 1;
124             }
125   
126             tri[++cnt1] = mid;
127         }
128         else
129         {
130             scanf("%lld", &q[++cnt2].k);
131             q[cnt2].i = i;
132             tri[++cnt1] = 0;
133         }
134     }
135     sort(distill + 1, distill + 1 + cnt3);
136     for (i = 1; i <= cnt3; i++)
137     {
138         qq[distill[i]] = i;
139     }
140   
141 //    cout << endl << endl;
142 //    for(i = 1; i <= cnt1; i++)
143 //        cout << i << " " << tri[i] << endl;
144 //
145 //    cout << endl << endl;
146 //    for(i = 1; i <= cnt2; i++)
147 //        cout << q[i].i << " " << q[i].k << endl;
148 //
149 //    cout << endl << endl;
150 //    for(i = 1; i <= cnt3; i++)
151 //        cout << distill[i] << " " ;
152 //
153 //    cout << endl << endl;
154   
155     if(cnt3 < 1)
156     {
157         for(i = 1; i <= cnt2; i++)
158         {
159             if(q[i].k == 0)
160                 printf("0\n");
161             else
162                 printf("-1\n");
163         }
164     }
165     else
166     {
167         build(1, 1, cnt3);
168       //  cout << "hello " << endl;
169   
170         j = 1;
171         for (i = 1; i <= cnt2; i++)
172         {
173         //    cout << "world!" << endl;
174             while (j < q[i].i)
175             {
176           //      cout << " ** " << qq[tri[j]] << " " << cnt3 << endl;
177                 update(1, qq[tri[j]], qq[tri[j]]);
178                 j++;
179             }
180   
181             if(q[i].k == 0)
182             {
183                 printf("0\n");
184             }
185             else
186             {
187                 tmp = query(1, q[i].k);
188                 if (tmp == -1)
189                     printf("-1\n");
190                 else
191                 {
192                     LL ans = ceil(sqrt((double)distill[tmp]));
193                     printf("%lld\n", ans);
194                 }
195             }
196   
197             j++;
198         }
199     }
200   
201   
202     return 0;
203 }
View Code

 

 
解法二:簡單線段樹
 
 
因爲查詢的是距離,且距離最多是1e5A,並且題目要求的是向上取整的整數值,所以直接按ceil(sqrt(x^2 + y ^2 + z ^2))距離建樹就好了。
 
AC代碼:
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <math.h>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <map>
  8 #include <stack>
  9 #include <deque>
 10 #include <iostream>
 11 using namespace std;
 12 typedef long long LL;
 13 const LL N = 200009;
 14  
 15 struct con
 16 {
 17     LL l, r;
 18 } con[4 * N];
 19 LL sum[4 * N];
 20 LL len;
 21  
 22 void pushUp(LL i)
 23 {
 24     sum[i] = sum[i << 1] + sum[i << 1 | 1];
 25 }
 26  
 27 void build(LL i, LL l, LL r)
 28 {
 29     con[i].l = l;
 30     con[i].r = r;
 31     if (con[i].l == con[i].r)
 32     {
 33         sum[i] = 0;
 34         return;
 35     }
 36     LL mid = (con[i].l + con[i].r) >> 1;
 37     build(i << 1, l, mid);
 38     build(i << 1 | 1, mid + 1, r);
 39  
 40     //pushUp(i);
 41 }
 42  
 43 void update(LL i, LL l, LL r)
 44 {
 45     // cout << " ** " << i << " " << con[i].l << " " << con[i].r << "  " << l << " " << r << endl;
 46  
 47     //if (con[i].l == l && con[i].r == r)
 48     if (con[i].l == l && con[i].r == r)
 49     {
 50         sum[i]++;
 51         return;
 52     }
 53     //LL mid = (con[i].l + con[i].r) >> 1;
 54  
 55     LL m = (con[i].l + con[i].r) >> 1;
 56     if (r <= m)
 57         update(i << 1, l, r);
 58     else
 59     {
 60         if (l > m)
 61             update(i << 1 | 1, l, r);
 62         else
 63         {
 64             update(i << 1, l, m);
 65             update(i << 1 | 1, m + 1, r);
 66         }
 67     }
 68 /*
 69     LL mid = (l + r) >> 1;
 70     if (len <= mid)
 71         update(i << 1, l, mid);
 72     else
 73     {
 74         update(i << 1 | 1, mid + 1, r);
 75     }
 76 */
 77     pushUp(i);
 78 }
 79  
 80 LL query(LL i, LL k)
 81 {
 82     // cout << " ?? " << i << " " << con[i].l << " " << con[i].r << " " << sum[i] << "   " << k << endl;
 83     if (sum[i] < k)
 84     {
 85         return -1;
 86     }
 87  
 88     if (con[i].l == con[i].r)
 89     {
 90         return con[i].r;
 91     }
 92  
 93     if (k <= sum[i << 1])
 94     {
 95         return query(i << 1, k);
 96     }
 97     else
 98     {
 99         return query(i << 1 | 1, k - sum[i << 1]);
100     }
101 }
102  
103 LL dis(LL x, LL y, LL z)
104 {
105     return ceil(sqrt(x * x + y * y + z * z));
106 }
107  
108 int main()
109 {
110     LL n, i, j, m, ans;
111     LL k, x, y, z;
112  
113     build(1, 0, N);
114     scanf("%lld", &n);
115     for (i = 1; i <= n; i++)
116     {
117         scanf("%lld", &m);
118         if (m == 1)
119         {
120             scanf("%lld%lld%lld", &x, &y, &z);
121             len = dis(x, y, z);
122             update(1, len, len);
123         }
124         else
125         {
126             scanf("%lld", &k);
127             if (k == 0)
128                 ans = 0;
129             else
130             {
131                 ans = query(1, k);
132             }
133             printf("%lld\n", ans);
134         }
135     }
136  
137     return 0;
138 }
View Code

 

 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章