Color the ball
Time Limit : 9000/3000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 10 Accepted Submission(s) : 3
Problem Description
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
Input
每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。
Output
每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
Sample Input
3
1 1
2 2
3 3
3
1 1
1 2
1 3
0
Sample Output
1 1 1
3 2 1
线段树: 注意必须用LAZY思想 否则必死
#include<stdio.h>
struct haha
{
int left;
int right;
int cover;
}node[100000*4];
int cnt,n;
void build(int left,int right,int nd)
{
node[nd].left=left;
node[nd].right=right;
node[nd].cover=0;
if(left==right) return ;
int mid=(node[nd].left+node[nd].right)/2;
build(left,mid,nd*2);
build(mid+1,right,nd*2+1);
}
void push(int nd)
{
if(node[nd].left==node[nd].right) return;
if(node[nd].cover)
{
node[nd*2].cover+=node[nd].cover;//我一 这个地方是加 不是直接附值
node[nd*2+1].cover+=node[nd].cover;
node[nd].cover=0;
}
return ;
}
void update(int left,int right,int nd)
{
if(node[nd].left==left&&node[nd].right==right)
{
node[nd].cover++;
push(nd);
return;
}
int mid=(node[nd].left+node[nd].right)/2;
if(right<=mid) update(left,right,nd*2);
else if(left>mid) update(left,right,nd*2+1);
else
{
update(left,mid,nd*2);
update(mid+1,right,nd*2+1);
}
push(nd);
}
void query(int nd)
{
push(nd);
if(node[nd].left==node[nd].right)
{
if(cnt!=n)
printf("%d ",node[nd].cover);
else printf("%d\n",node[nd].cover);
cnt++;
return ;
}
query(nd*2);
query(nd*2+1);
}
int main()
{
int i;
while(scanf("%d",&n)&&n!=0)
{
cnt=1;
build(1,n,1);
for(i=1;i<=n;i++)
{
int s,e;
scanf("%d %d",&s,&e);
update(s,e,1);
}
query(1);
}
return 0;
}
树状数组
#include<stdio.h>
#include<string.h>
int c[100000+5],n;
int Lowbit(int k)
{
return (k&-k);
}
void update(int pos,int num)
{
while(pos<=n)
{
c[pos]+=num;
pos+=Lowbit(pos);
}
}
int sum(int pos)
{
int s=0;
while(pos>0)
{
s+=c[pos];
pos-=Lowbit(pos);
}
return s;
}
int main()
{
int i,j,s,e;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
memset(c,0,(n+3)*sizeof(c[0]));
for(i=1;i<=n;i++)
{
scanf("%d %d",&s,&e);
update(s,1);
update(e+1,-1);
}
for(i=1;i<n;i++)
printf("%d ",sum(i));
printf("%d\n",sum(i));
}
return 0;
}
针对上面的插线问点。。。有两种求解办法。。
对于区间a——b:如果插入一个数1
第一种:update(a,1)和update(b+1,-1) 查询方式直接Quary(p)
第二种:for(int i=a;i<=b;++i) update(i,1) 查询方式Quary(p)-Quary(p-1);
一般人都用第一种更新方法。。。
其实上面那种方法 就是 举个例子吧
数组:
0 0 0 0 0 0 0 0 0 数组内容
0 1 2 3 4 5 6 7 8 数组编号
2-4染了一次后变成了
0 1 0 0 0 -1 0 0 0 数组内容
0 1 2 3 4 5 6 7 8 数组编号
3-7染了一次后
0 1 0 1 0 -1 0 0 -1 数组内容
0 1 2 3 4 5 6 7 8 数组编号
那么查询3的时候就是 3及其之前所有元素的和 2 (这就是数组数组中的查询sum操作)
查询6的时候就是6及其之前的所有元素和1