hdu1556Color the ball线段树区间更新

时间:2024-10-23 11:04:44

题目链接

线段树区间更新更新一段区间,在更新区间的过程中,区间被分成几段,每一段的左右界限刚好是一个节点的tree[node].left和tree[node].right(如果不是继续分,直到是为止)

区间几次更新后,进行查询,查询的过程就可以看成重走了更新的过程,所以第一种代码中ans+=A[k].count;

ans就是最后答案

 #include"stdio.h"
#include"string.h"
#include"stdlib.h"
struct tree
{
int x,y,mid;
int count;
}A[]; void creat(int x,int y,int k)
{
A[k].x=x;
A[k].y=y;
int mid=(x+y)/;
A[k].count=;
if(x==y)return ;
creat(x,mid,*k);
creat(mid+,y,*k+);
} void insert(int x,int y,int k)
{
if(A[k].x==x&&A[k].y==y)
{
A[k].count++;return;
}
int mid=(A[k].x+A[k].y)/;
if(x>mid)insert(x,y,*k+);
else if(y<=mid)insert(x,y,*k);
else
{
insert(x,mid,*k);
insert(mid+,y,*k+);
} } int ans;
void search(int t,int k)
{
ans+=A[k].count; if(A[k].x==A[k].y&&A[k].x==t)return ;
int mid=(A[k].x+A[k].y)/;
if(t<=mid)search(t,*k);
else search(t,*k+);
} int main()
{
int n,i;
int a,b;
while(scanf("%d",&n)!=-&&n)
{
creat(,n,);
for(i=;i<n;i++)
{
scanf("%d%d",&a,&b);
insert(a,b,);
}
for(i=;i<n;i++)
{
ans=;
search(i,);
printf("%d ",ans);
}
ans=;
search(i,);
printf("%d\n",ans);
}
return ;
}

在第二种代码中其实思路是一样的,

if ( seg[idx].l == l && seg[idx].l )
{
seg[idx].cnt++;//这个节点被刷了一次,但实际上是要求seg[idx].l到seg[idx].r的区间都刷一次的,l~r就对应了相应的序号的气球
return;
}

for (int i = seg[idx].l; i <= seg[idx].r; i++)
ans[i] += seg[idx].cnt;//所以在这个区间里,相应的气球都刷一次

 #include <stdio.h>
#include <string.h> const int MAXN = ; typedef struct {
int cnt;
int l;
int r;
}Node; Node seg[ * MAXN];
int ans[MAXN]; void build(int idx,int l,int r)
{
seg[idx].l = l;
seg[idx].r = r;
seg[idx].cnt = ; if ( l == r )
return; int mid = ( l + r ) >> ;
build(idx << , l, mid);
build((idx << ) + , mid + , r);
} void color(int idx,int l,int r)
{
if ( seg[idx].l == l && seg[idx].l )
{
seg[idx].cnt++;//这个节点被刷了一次,但实际上是要求seg[idx].l到seg[idx].r的区间都刷一次的,l~r就对应了相应的序号的气球
return;
} int mid = ( seg[idx].l + seg[idx].r ) >> ;
if ( r <= mid )
color(idx << , l, r);
else if ( mid + <= l )
color((idx << ) + , l, r);
else
{
color(idx << , l, mid );
color((idx << ) + , mid + , r);
}
} void solve(int idx)
{
for (int i = seg[idx].l; i <= seg[idx].r; i++)
ans[i] += seg[idx].cnt;//所以在这个区间里,相应的气球都刷一次 if ( seg[idx].l == seg[idx].r )
return; solve(idx << );
solve((idx << ) + );
} int main()
{
// freopen("1.txt","r",stdin); int N;
while ( scanf("%d",&N) == )
{
memset(ans, , sizeof(ans));
memset(seg, , sizeof(seg)); if ( N == )
break; build(,,N);
int p,q; for (int i = ; i < N; i++)
{
scanf("%d%d",&p,&q);
color(,p,q);
} solve(); for ( i = ; i <= N; i++)
printf("%d%c",ans[i], ( i == N ) ? '\n' : ' ' ); } return ;
}

第三种代码则有些不同,上面两种代码在更新的时候只更新到了满足left==seg[n].left&&right==seg[n].right的节点,并未继续更新下去直到节点。

而第三种代码则更新到了节点,所以查询代码也是直接查询节点。

 //不更新所有的节点,如果seg[n].v=0说明这一段是混合的,由他的子节点分开表示

 #include<stdio.h>
#define MAXN 100005
class seg_tree
{
public:
int mid(){return (left+right)/;};
int left,right,v;
}seg[*MAXN];
void build(int n,int left,int right)
{
seg[n].left=left;
seg[n].right=right;
seg[n].v=;
if(seg[n].left==seg[n].right)return ;
build(*n,left,seg[n].mid());
build(*n+,seg[n].mid()+,right);
} void update(int n,int left,int right)
{
if(left==seg[n].left&&right==seg[n].right)
{
seg[n].v++;
return ;
}
if(seg[n].v>)//向下更新
{
seg[*n].v+=seg[n].v;
seg[*n+].v+=seg[n].v;
seg[n].v=;//代表这个节点往下的一次更新结束
}
if(right<=seg[n].mid())update(*n,left,right);
else if(left>seg[n].mid())update(*n+,left,right);
else
{
update(*n,left,seg[n].mid());
update(*n+,seg[n].mid()+,right);
}
}
int query(int n,int index)
{
if(seg[n].left==seg[n].right)
{
return seg[n].v;
}
if(index<=seg[n].mid())return seg[n].v+query(*n,index);
else return seg[n].v+query(*n+,index);
} int main()
{
int n,i,x,y;
//freopen("a.txt","r",stdin);
while(scanf("%d",&n)&&n)
{
build(,,n);
for(i=;i<=n;i++)
{
scanf("%d%d",&x,&y);
update(,x,y);
}
printf("%d",query(,));
for(i=;i<=n;i++)printf(" %d",query(,i));printf("\n");
}
return ;
}