您的位置:首页 > 编程语言 > C语言/C++

线段树专题#2_蒟蒻训练历程记录_HDU5775

2016-07-29 15:34 393 查看
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>//线段树单点更新查询
using namespace std;
typedef long long ll;
#define N 100010
int g[4*N];
typedef struct A{
int w;
int pos1;
int add;
}A;
A a
;

bool cmp(A a, A b)
{
return a.w < b.w;
}

void init(int rt, int l , int r)//递归建立线段树
{
if(l == r)
{
g[rt] = 0;
return;
}
int mid = (l+r) >> 1;
init(rt<<1, l, mid);
init(rt<<1|1, mid+1, r);
g[rt] = 0;
}

int find(int rt, int l, int r, int L, int R)//递归查询
{
if(l >= L && r <= R)
{
return g[rt];
}
int k1 = 0, k2 = 0;
int mid = (l+r) >> 1;
if(mid >= L)//这个地方区间要跟所查询的总区间相比较而不是目前查询的区间
{
k1 = find(rt<<1, l, mid, L, R);
}
if(mid < R)
{
k2 = find(rt<<1|1, mid+1, r, L, R);
}
return k1+k2;
}

void update(int rt, int l, int r, int x)//要记住一直更新的都是现在的根节点。。
{
if(l == r && l == x)
{
g[rt]++;
return;
}
int mid = (l+r) >> 1;
if(x <= mid)//这回是拿查找的值跟mid作比较
{
update(rt<<1, l, mid, x);
g[rt]++;//这个地方更新错了。。
}
if(mid < x)
{
update(rt<<1|1, mid+1, r, x);
g[rt]++;
}
}

int main()
{
int t, num = 0;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i].w);
a[i].pos1 = i;
}
init(1, 1, n);//初始化建树
for(int i = n; i >= 1; i--)
{
if(a[i].w == 1)
a[i].add = 0;
else
a[i].add = find(1, 1, n, 1, a[i].w-1);
update(1, 1, n, a[i].w);//不管是不是1都要更新啊。。
}
sort(a+1, a+n+1, cmp);
printf("Case #%d:", ++num);
for(int i = 1; i <= n; i++)
{
int t1 = min(a[i].pos1, i);
int t2 = a[i].pos1+a[i].add;
//printf("%d %d %d\n", i, a[i].pos1, a[i].add);
printf(" %d", t2-t1);
}
printf("\n");
}
return 0;
}

               这道题楼主思路想对了,就是寻找数组中的一个元素前面比它大的个数和后面比它小的个数取最大值。可是比赛的时候完全没有想到用线段树来进行查询啊。。。于是生无可恋脸的磨完了比赛~啊啊太弱了好忧桑~还是好好训练吧~o( ̄ε ̄*)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息