北京信息科技大学第十一届程序设计竞赛I:andy种树 (线段树 差分)

https://ac.nowcoder.com/acm/contest/940/I
 

题目描述

andy在他的庄园里种了n棵树,排列成一排,标号为1到n。最开始的时候n棵树的高度都是0,也就是种子刚刚被埋下,树还没有长出来。

andy会一种魔法,他每使用一次魔法,就可以让树标号落在连续区间[l, r]里的树的高度增加1。他可以使用q次这种魔法,然后他很好奇,在使用了q次魔法之后,他的所有树的高度分别是多少呢?

输入描述:

第一行输入两个整数n,q。(1<= n, q <= 1e5)

接下来q行,每行输入两个整数l, r(l <= r),表示andy让标号落在区间[l, r]里的数高度都加1

输出描述:

输出有一行n个整数,每个整数后面有空格。输出末尾没有换行

第i个数表示第i棵树的高度

示例1

输入

复制

10 3
1 3
2 4
3 3

输出

复制

1 2 3 1 0 0 0 0 0 0

说明

andy种了10棵树

第一次使用魔法使得1、2、3棵树的高度增加1,

所有树的高度为

1 1 1 0 0 0 0 0 0 0

第二次使用魔法使得2、3、4棵树的高度增加1,

所有树的高度为

1 2 2 1 0 0 0 0 0 0

第三次使用魔法使得第3棵树的高度增加1

所有树的高度为

1 2 3 1 0 0 0 0 0 0

解题思路:

线段树区间修改模板。

现在对线段树有一些了解,但是还是不太熟练。

#include<bits/stdc++.h>
using namespace std;
int n, p, m, ans;
struct node
{
    int l,r,w,f;
}tree[400001];
void build(int k,int ll,int rr)
{
    tree[k].l=ll,tree[k].r=rr;
    if(tree[k].l==tree[k].r)
    {
       	tree[k].w=0;
    	return;
    }
    int m=(ll+rr)/2;
    build(k*2,ll,m);
    build(k*2+1,m+1,rr);
}
void down(int k)
{
    tree[k*2].f+=tree[k].f;
    tree[k*2+1].f+=tree[k].f;
    tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
    tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
    tree[k].f=0;
}
void change_interval(int k, int a, int b)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w+=(tree[k].r-tree[k].l+1);
        tree[k].f+=1;
        return;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)/2;
    if(a<=m) change_interval(k*2, a, b);
    if(b>m) change_interval(k*2+1, a, b);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}

void ask_point(int k, int x)
{
    int m;
    if(tree[k].l==tree[k].r)
    {
        ans=tree[k].w;
        return ;
    }
    if(tree[k].f) down(k);
    m=(tree[k].l+tree[k].r)/2;
    if(x<=m) ask_point(k*2, x);
    else ask_point(k*2+1, x);
}
int main()
{
    int i, a, b;
    scanf("%d",&n);
    build(1, 1, n); 
    scanf("%d",&m); 
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        change_interval(1, a, b);
    }
    for(i=1; i<=n; i++)
    {
    	ask_point(1,i);
    	printf("%d ", ans);
    }	
    return 0;
}

后来看了别人代码,这是一道差分裸题。

#include<bits/stdc++.h>
using namespace std;
#define N 100020
int a[N];
int main()
{
    int n, q, i, l, r;   
    scanf("%d%d", &n, &q);
    while(q--)
    {
        scanf("%d%d", &l, &r);
        a[l]++;
        a[r+1]--;
    }
    for(int i=1;i<=n;i++){
        a[i]+=a[i-1];
        printf("%d ", a[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zyq1758043090/p/11852640.html