原来那篇文章不知怎么没了,只好再写一份
题目传送门
A题:
第一次写线段树,写的不太顺。
这道题的数据是按y轴顺序给出的,所以,以x轴顺序建树即可,另外由于前面输入的点的纵坐标一定<= 后面输入的点的纵坐标值,所以,插入点跟查询写在一个循环里,这样正好可以省掉处理y轴的步骤。另外注意线段树的大小是数据量的4倍。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MaxN = 15005;
const int MaxX = 32005;
int x[MaxN], y;
int tree[4 * MaxX] = {0};
int lev[MaxN] = {0};
void buildtree (int p, int l, int r, int t);
int findtree (int p, int l, int r, int tl, int tr);
int main()
{
int n;
scanf("%d", &n);
int maxx = 0;
for(int i=0; i<n; i++){
scanf("%d%d", &x[i], &y);
if(x[i] > maxx) maxx = x[i];
}
memset(tree, 0, sizeof(tree));
memset(lev, 0, sizeof(lev));
for(int i=0; i<n; i++){
buildtree(1, 0, maxx, x[i]);
lev[findtree(1, 0, maxx, 0, x[i]) - 1]++;
/*for(int i=0; i<4*n; i++)
printf("%d ", tree[i]);
printf("\n");*/
}
for(int i=0; i<n; i++)
printf("%d\n", lev[i]);
return 0;
}
void buildtree (int p, int l, int r, int t)
{
if(l == r) {tree[p]++; return;}
int mid = (l + r) >> 1;
if(t <= mid) buildtree(2*p, l, mid, t);
else buildtree(2 * p + 1, mid + 1, r, t);
tree[p] = tree[2 * p] + tree[2 * p + 1];
return;
}
int findtree(int p, int l, int r, int tl, int tr)
{
if(tl <= l && tr >= r) {return tree[p];}
int mid = (l + r) >> 1;
if(mid >= tr) return findtree(2 * p, l, mid, tl, tr);
if(mid < tl) return findtree (2*p+1, mid+1, r, tl, tr);
int ans = findtree(2 * p, l, mid, tl, tr) + findtree(2*p+1, mid+1, r, tl, tr);
return ans;
}
B题:略掉;
C题:
吐槽一下:这也叫基础题?!
基本方法是从后往前推,第i头牛在前i头牛中的编号是a[i] + 1,然后计算出后 n-i 头牛中编号比第i头牛小的牛的个数,两数相加就是第i头牛的实际编号;
递推代码(便于理解算法):
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MaxN = 8000 + 5;
int a[MaxN];
int sure[MaxN] = {0};
int n;
int main()
{
a[0] = 0;
scanf("%d", &n);
for(int i=1; i<n; i++)
scanf("%d", &a[i]);
for(int i=n-1; i>=0; --i){
int t = a[i] + 1;
for(int j=1; j<=t; j++){
if(sure[j])a[i]++, t++;
}
sure[a[i] + 1] = 1;
//printf("%d\n", a[i] + 1);
}
for(int i=0; i<n; i++){
printf("%d\n", a[i] + 1);
}
return 0;
}
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MaxN = 8000 + 5;
int a[MaxN];
int sure[MaxN] = {0};
int n;
int main()
{
a[0] = 0;
scanf("%d", &n);
for(int i=1; i<n; i++)
scanf("%d", &a[i]);
for(int i=n-1; i>=0; --i){
int t = a[i] + 1;
for(int j=1; j<=t; j++){
if(sure[j])a[i]++, t++;
}
sure[a[i] + 1] = 1;
//printf("%d\n", a[i] + 1);
}
for(int i=0; i<n; i++){
printf("%d\n", a[i] + 1);
}
return 0;
}
D题,E题略掉;
F题:
这道题跟B题很像,参考B题的思路,从后往前推,很快就能推出算法,
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MaxN = 200000 + 5;
int tree[ 4 * MaxN];
int num[MaxN], loc[MaxN];
int a[MaxN];
void build(int p, int l, int r);
int query(int p, int l, int r, int t);
int main()
{
int n;
while(~scanf("%d", &n)){
memset(a, -1, sizeof(a));
for(int i=0; i<n; i++){
scanf("%d%d", &loc[i], &num[i]);
}
build(1, 1, n);
for(int i=n-1; i>-1; --i){
a[query(1, 1, n, loc[i] + 1)] = num[i];
}
for(int i=1; i<=n; i++)
printf("%d ", a[i]);
printf("\n");
}
return 0;
}
void build(int p, int l, int r)
{
tree[p] = r - l + 1;
if(l == r) return;
int mid = (l + r) >> 1;
build(2 * p , l, mid);
build(2 * p + 1, mid + 1, r);
}
int query(int p, int l, int r, int t)
{
tree[p]--;
if(l == r)return l;
int ans, mid = (l + r) >> 1;
if(t <= tree[2 * p]) ans = query(2 * p, l, mid, t);
else ans = query(2 * p + 1, mid + 1, r, t - tree[2 * p]);
return ans;
}