luogu P1168 中位数
窒息
这道题令我头秃
问了问学长思路
学长如是说:
“这道题有很多种解题方法,但是你想用线段树对吧
可以用平衡树来解决,但是你不会,还有主席树,你也不会,
我又想到了一种需要离散化的线段树做法……”
(所以说那么多我不会的干什么啊!
这道题我看了很多题解都没看懂
大概是因为用线段树做有一个数组num记录的是什么没有理解
那思路嘛
求中位数
首先开一个线段树,每当出现一个数时,便把那个数所在的数组加一,表示出现次数
当你找中位数的时候,从根开始,分别看左子树和右子树的区间和
如果要找的中位数的位置,即编号x,小于左子树的区间和l
那么该中位数就在左子树中
反之,则在右子树的x - l位置上
emmmm哇还是画图比较好
(然而我没有画图软件所以请自己画一画体验一下
看一下代码吧
#include<cstdio> #include<algorithm> using namespace std; #define maxn 100010 struct TREE { int l,r,num; } tree[maxn << 2];//开四倍啊我一开始忘了wa了两个点 int a[maxn],b[maxn];//a是原数组,b是排序去重后的 void build(int l,int r,int now) { tree[now].l = l; tree[now].r = r; int mid = (l + r) >> 1; if(l == r) return ; build(l,mid,now << 1); build(mid + 1,r,now << 1 | 1); }//建树的处理 void update(int now,int k) {//当一个位置上有数的时候更新一下,num++ ++tree[now].num; if(tree[now].l == tree[now].r) return ; int mid = (tree[now].l + tree[now].r) >> 1; if(k <= mid) update(now << 1,k); else update(now << 1 | 1,k); } int query(int now,int x) { if(tree[now].l == tree[now].r) return tree[now].l; if(x <= tree[now << 1].num)//如果小于左子树区间和,则中位数在左子树中 return query(now << 1,x); else//反之在右子树里,这是x在右子树中的位置是x - num return query(now << 1 | 1,x - tree[now << 1].num); } int main() { int n; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); b[i] = a[i]; } sort(b + 1,b + n + 1); int k = unique(b + 1,b + n + 1) - b;//将b排序去重 build(1,n,1); // for(int i = 1;i < k;i++) // printf("qwq %d ",b[i]); // printf("\n"); for(int i = 1; i <= n; i++) { int www = lower_bound(b + 1,b + k + 1,a[i]) - b;//求出每次插入的数的位置 // printf("qwq %d %d qwq\n",a[i],www); update(1,www); if(i % 2) printf("%d\n",b[query(1,i / 2 + 1)]);//输出中位数所在位置上的数 } return 0; }
大概还比较详细吧www
(最后说一下,ljq学长穿了一件帅气的新衬衫哈哈哈哈哈wxsl
————————————————————几分钟的分割线————————————————————————
阿对
还有一种短一点的写法
#include<cstdio> #include<algorithm> using namespace std; #define maxn 100010 struct QAQ { int data,num; } a[maxn]; int sum[maxn * 4],rank[maxn]; int cmp(QAQ x,QAQ y){ return x.data < y.data; } void insert(int now,int l,int r,int x) { sum[now]++; if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) insert(now * 2,l,mid,x); else insert(now * 2 + 1,mid + 1,r,x); } int query(int now,int l,int r,int k) { if(l == r) return l; int mid = (l + r) >> 1; if(sum[now * 2] >= k) return query(now * 2,l,mid,k); else return query(now * 2 + 1,mid + 1,r,k - sum[now * 2]); } int main() { int n; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i].data); a[i].num = i; } sort(a + 1,a + n + 1,cmp); for(int i = 1; i <= n; i++) rank[a[i].num] = I;//这里的离散化就不太一样反正懂就好了www for(int i = 1; i <= n; i++) { insert(1,1,n,rank[i]); if(i % 2) printf("%d\n",a[query(1,1,n,i / 2 + 1)].data); } return 0; } //道理都一样就是没有提前建树短一些23333