题目
poj1282
看到这道题我就知道我写过,但是我忘了。
- 我们直接的做法就是 从高到低排序,个子相同k从小到达排序,挨个放入vector里面,采用vector的insert插入到第几个数。。每次insert复杂度是o(n)。。
- 还有一种思路是 从低到高排序,格子相同k从大到小排序。k一定要从大到小!!
举个例子把:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 排序后就是:[[4,4], [5,2], [5,0], [6,1],[7,1],[7,0]] ;
[4,4]想要前面有4个比他大的,所以[4,4]要放在第5个空格,-- – -- – [4,4] –
[5,2]想要前面有2个比他大的,所以[5,2]要放在目前还剩空格的第3个空格,-- – [5,2] – [4,4] –
[5,0]想要前面有0个比他大的,所以[5,0]要放在目前还剩空格的第1个空格,[5,0] – [5,2] – [4,4] –
[6,1]想要前面有1个比他大的,所以[6,1]要放在目前还剩空格的第2个空格,[5,0] – [5,2] [6,1] [4,4] –
[7,1]想要前面有1个比他大的,所以[7,1]要放在目前还剩空格的第2个空格,[5,0] – [5,2] [6,1] [4,4] [7,1]
[7,0]想要前面有0个比他大的,所以[7,0]要放在目前还剩空格的第1个空格,[5,0] [7,0 [5,2] [6,1] [4,4] [7,1]
为什么k要从大到小排序呢?
我们看后两个[7,1] [7,0] 假如先将[7,0]放在剩余的第一个空格,[7,1]就要放在剩余的第二个空格,而放完[7,0]后只剩余1个空格了。。换而言之,谁先放,就代表它前面还有空格要求,[7,1]要求前面有1个空格,所以要比[7,0]先放。
现在已经转化为找第p[i][1]+1的空格问题了。每次找到后我们又要把这个空格置为非空,涉及到修改,我们就用树状数组来维护。如何找到第k个空格,可以二分+树状数组,也可以直接倍增。
下面就是倍增代码:res+1就是第k+1个空格。注意想要得到第x个空格,一定要query_Kth(x-1)。
因为我们只会 求 只包含x个空格的最远的长度。比如 [1,3],[1,5]包含x个空格,[1,6]包含x+1个空格,返回5.
int query(int k){//放到第k个空格。
--k;
int res=0;
for(int i=C;i>=0;--i)
if(res+(1<<i)<MX&&k>=val[res+(1<<i)]) k-=val[res+=(1<<i)];
add(res+1,-1);
return res+1;//返回第k个空格的下标(从1开始)
}
class Solution {
#define low(x) ((x)&(-x))
#define C 10
public:
int MX,*val;
void add(int x,int v){
for(;x<MX;x+=low(x)) val[x]+=v;
}
int query(int k){//放到第k个空格。
--k;
int res=0;
for(int i=C;i>=0;--i)
if(res+(1<<i)<MX&&k>=val[res+(1<<i)]) k-=val[res+=(1<<i)];
add(res+1,-1);
return res+1;
}
vector<vector<int>> reconstructQueue(vector<vector<int>>& a) {
int n=a.size();MX=n+1,val=new int[MX];
for(int i=1;i<=n;++i) val[i]=0;
for(int i=1;i<=n;++i) add(i,1);
sort(a.begin(),a.end(),[&](vector<int>&x,vector<int>&y)->bool{
return (x[0]==y[0])?(x[1]>y[1]):(x[0]<y[0]);
});
vector<int>empty;
vector<vector<int>>ans(n,empty);
for(int i=0;i<n;++i) ans[query(a[i][1]+1)-1]=a[i];
return ans;
}
};