离散化+线段树+二分查找

牛客 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 
  2 #include 
  3 #include <string.h>
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include 
  9 #include 
 10 #include 
 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 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 
  2 #include 
  3 #include <string.h>
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include 
  9 #include 
 10 #include 
 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

 

 
 
 

你可能感兴趣的:(离散化+线段树+二分查找)