思想升华
逐层访问树结构而非深度访问树结构
题目
思路
要求
第i轮,找出最长0串(有两个选左边那个),将该串中间的0(怎么求中间是谁题目给了)赋值为i
思路
- 看起来像树结构:先访问父结点,然后访问它的左子节点后访问它的右子节点,再访问他们各自的儿子
->但实际上不是,像只是因为每次操作后都诞生了两个平分的更小的子问题
->但考虑到树是深度访问,必须一直访问左树到叶子才会回来访问右节点,故不是树
->相反,该题其实类似于将树逐层访问(从最大的根层 到 第二层 到…叶子层)
->如果真的是对半分只需要一个队列就是(分词分成两个部分就把他们先放入队列不做->上一层没访问完就不会访问下一层,就不会出现下下层->做到了逐层访问)
->实际不是极限对半分
->用优先队列根据大小排序,保证满足题意
难点
因为有二叉树的特点误以为是用树的常规访问(深度访问)来做了
代码
我的代码
#include<iostream>
#include<queue>
using namespace std;
const int N = 2e5+10;
struct node
{
int l, r, len;
node(int a, int b, int c) {l=a, r=b, len=c;};
bool operator < (const node &b) const {
if(len == b. len) return l > b.l;//右边的更小
else return len < b.len;//短的更小
}
};
priority_queue<node> q;
int a[N];
int main()
{
//freopen("C:\\Users\\bearb\\Desktop\\in.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
//init
int cnt = 0;
for(int i = 1; i <= n; i++) a[i] = 0;
//operate
q.push(node(1, n, n));
while(!q.empty())//不为空,继续做
{
node x=q.top();
q.pop();
//中点
int mid;
if(x.len%2) mid = (x.l+x.r)/2;
else mid = (x.l+x.r-1)/2;
a[mid]=++cnt;
if(mid-1>=x.l) q.push(node(x.l, mid-1, mid-x.l));
if(mid+1<=x.r) q.push(node(mid+1, x.r, x.r-mid));
}
//cout
cout <<a[1];
for(int i = 2; i <= n; i++) cout << " "<<a[i];
cout << endl;
}
return 0;
}