1544.中位数
经过尝试每次pop前sort是会超时的(doge)
双堆维护中位数区域,一个大根堆一个小根堆,自己思考一下就知道思路了
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
priority_queue<int>little;
priority_queue<int,vector<int>,greater<int>>bigger;
void check(){
if(bigger.size()>little.size()){
little.push(bigger.top());bigger.pop();
}else if(little.size()>bigger.size()+1){
bigger.push(little.top());little.pop();
}
if(little.empty()){
little.push(bigger.top());bigger.pop();
}
}
int main(){
char op[6];
while(scanf("%s",op)!=EOF){
int x;
if(op[1] == 'u'){
scanf("%d",&x);
if(little.empty() || x<little.top())little.push(x);
else bigger.push(x);
check();
}else{
int res = little.top();little.pop();
check();
printf("%d\n",res);
}
}
}
1551.二叉树合并
这里对于建树的节点不能用的时候才创建,因为需要提前根据下标进行左右孩子的指向,所以提前为两棵树的100个节点进行内存分配初始化。
其次,在对于储存前序中序结果的数组中,数组大小一定要能够容纳合并前两棵树所有节点的大小(有可能两棵树除了根节点相同,其它点都错位分布)
#include<iostream>
using namespace std;
struct node {
int var;
node*l;
node*r;
node(int x): var(x), l(nullptr), r(nullptr) {}
};
node* tree1[110];
node* tree2[110];
node* root;
node* solve(node*a, node*b) {
if(a == nullptr)return b;
if(b == nullptr)return a;
a->var += b->var;
a->l = solve(a->l, b->l);
a->r = solve(a->r, b->r);
return a;
}
void init(){
for(int i = 1;i<=100;i++){
tree1[i] = new node(0);
tree2[i] = new node(0);
}
}
int cnt;
int arr[210][2];
void pre(node* x){
if(x == nullptr)return ;
// printf("%d\n",x->var);
arr[cnt++][0] = x->var;
pre(x->l);
pre(x->r);
}
void mid(node* x){
if(x == nullptr)return ;
mid(x->l);
arr[cnt++][1] = x->var;
mid(x->r);
}
void output(int k){
printf("%d",arr[0][k]);
for(int i = 1;i<cnt;i++)printf(" %d",arr[i][k]);
printf("\n");
}
int main() {
init();
int t;
scanf("%d", &t);
while (t--) {
int n;
cnt = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int l, r;
scanf("%d%d%d", &tree1[i]->var, &l, &r);
if (l)tree1[i]->l = tree1[l];
else tree1[i]->l = nullptr;
if (r)tree1[i]->r = tree1[r];
else tree1[i]->r = nullptr;
}
// for(int i = 1;i<=n;i++){
// printf("%d->%d,%d\n",i,tree1[i]->l==nullptr?0:tree1[i]->l->var,tree2[i]->r==nullptr?0:tree1[i]->r->var);
// }
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int l, r;
scanf("%d%d%d", &tree2[i]->var, &l, &r);
if (l)tree2[i]->l = tree2[l];
else tree2[i]->l = nullptr;
if (r)tree2[i]->r = tree2[r];
else tree2[i]->r = nullptr;
}
root = solve(tree1[1], tree2[1]);
pre(root);
cnt = 0;
mid(root);
output(0);
output(1);
}
}
1554.二叉查找树
与其说高度,其实不如说成深度更好理解,因为高度来看根节点应该是最高的,对于这题不是最优思路。
根节点视作深度为1,那么很容易想到新增的深度就是它父节点的深度+1,其他操作就是建一棵BST的基本操作吧,没什么思考量
#include<iostream>
using namespace std;
struct node{
int var,h;
node *l;
node *r;
node(int v,int h):var(v),h(h),l(nullptr),r(nullptr){}
};
int ans , n;
node *root;
void insert(int cur,node *fa){
if(cur<fa->var){
if(fa->l)insert(cur,fa->l);
else {
ans += fa->h+1;
fa->l = new node(cur,fa->h+1);
}
}else{
if(fa->r)insert(cur,fa->r);
else {
ans += fa->h+1;
fa->r = new node(cur,fa->h+1);
}
}
}
void build(){
int x;
scanf("%d",&x);
root = new node(x,1);
for(int i = 1;i<n;i++){
scanf("%d",&x);
insert(x,root);
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
ans = 1;
scanf("%d",&n);
build();
printf("%d\n",ans);
}
}
1557.树
我个人喜欢prim算法一些,只用排序、然后找连通分支,最后取边(最小生成树的套路,只不过每次取边都从大的开始取。)
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int a,b,w;
};
node v[20010];
int fa[2010];
bool cmp(node a,node b){
return a.w>b.w;
}
int find(int a){ //找连通分支
//并查集中的递归写法
if(fa[a] == a)return a;
fa[a] = find(fa[a]);
return fa[a];
}
int n,m,all,maxTree;
int main(){
int t;
scanf("%d",&t);
while(t--){
all = maxTree = 0;
scanf("%d%d",&n,&m);
for(int i = 0;i<m;i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);all+=w;
v[i].a = a;v[i].b = b;v[i].w = w;
fa[a] = a;fa[b] = b;
// 初始化每个点的连通分支根为自己(没取这条边的话,这两个点显然暂时不是一个分支)
}
sort(v,v+m,cmp);
int k = 0,cnt = 0;
while(cnt<n-1){
int fx = find(v[k].a),fy = find(v[k].b);
if(fx!=fy){
// 每次找分支都是递归查询,只需要改根节点间的连通关系,其他相关点在之后的查询中会自动更新