Countless Candies | ||||||
| ||||||
Description | ||||||
小w喜欢吃糖果,一次偶然的机会,小w再次邂逅了阿拉神灯。 阿拉神灯知道小w的心意之后问:你想要多少糖哈,亲~ 小w笑答:不要太多啦,吃不完就够了~ 阿拉神灯:¥^ @ % & * R & ^... 善良的小w想把这些糖果分一些给自己的好朋友。小w有N 个好朋友,编号从1到N。小w要分N次,每次操作如下:[L, R]表示给编号在L到R 的朋友每人一块糖。最后,小w想知道每个朋友分得了多少糖果,由于人缘太好,朋友太多而没法统计,请帮助小w计算一下最后的结果吧。 | ||||||
Input | ||||||
第 1 行:一个整数N 表示朋友的数量(1 ≤N≤100000) 第 2到N+1行:每行两个整数L,R,表示编号在[L, R]内的朋友,每人分得一块糖。 多组测试数据,处理到文件结束。 | ||||||
Output | ||||||
N 个整数表示每个朋友得到的糖果的数量,每组测试数据占一行。 | ||||||
Sample Input | ||||||
4 1 2 2 3 1 3 1 4 | ||||||
Sample Output | ||||||
3 4 3 1 |
操作次数很多的加数据的题目,直接上线段树~
/*
2016/2/3 13:17
hlg 1566 Countless Candies
线段树区间更新、点查询
*/
#include<stdio.h>
#include<string.h>
using namespace std;
#define lson l,m,rt*2
#define rson m+1,r,rt*2+1
int tree[1000000];
int flag[1000000];
void pushup(int rt)
{
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void pushdown(int l,int r,int rt)//向下维护树内数据
{
if(flag[rt])//如果贪婪标记不是0(说明需要向下进行覆盖区间(或点)的值)
{
int m=(l+r)/2;
flag[rt*2]+=flag[rt];
flag[rt*2+1]+=flag[rt];
tree[rt*2]+=(m-l+1)*flag[rt];//千万理解如何覆盖的区间值(对应线段树的图片理解(m-l)+1)是什么意识.
tree[rt*2+1]+=(r-(m+1)+1)*flag[rt];
flag[rt]=0;
}
}
void build( int l ,int r , int rt )
{
if( l == r )
{
tree[rt]=0;
flag[rt]=0;
}
else
{
int m = (l+r)>>1 ;
build(lson) ;
build(rson) ;
pushup(rt) ;
}
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)//覆盖的是区间~
{
tree[rt]+=c*((r-l)+1);//覆盖当前点的值
flag[rt]+=c;//同时懒惰标记~!
return ;
}
pushdown(l,r,rt);
int m=(l+r)/2;
if(L<=m)
{
update(L,R,c,lson);
}
if(m<R)
{
update(L,R,c,rson);
}
pushup(rt);
}
int Query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return tree[rt];
}
else
{
pushdown(l,r,rt);
int m=(l+r)>>1;
int ans=0;
if(L<=m)
{
ans+=Query(L,R,lson);
}
if(m<R)
{
ans+=Query(L,R,rson);
}
return ans;
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(tree,0,sizeof(tree));
memset(flag,0,sizeof(flag));
build(1,n,1);
for(int i=0;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
update(x,y,1,1,n,1);
}
printf("%d",Query(1,1,1,n,1));
for(int i=2;i<=n;i++)
{
int ans=Query(i,i,1,n,1);
printf(" %d",ans);
}
printf("\n");
}
}