这道线段树的题目纠结了好长时间,本来的想法真是太天真了,向线段树里面插入一段线段,当时错误的想法是他的所有的子树同样要更新,这样效率自然就下降了,TLE了很长时间,后来才想出来计算(i,i)被涂色的次数,只要插入的线段包含这个区间,就把它加起来,最后求和。这道题用树状数组做挺简单,但是还没学过树状数组是神马东西,以后再学了
#include<stdio.h>
int N;
const int MAX=100010;
struct line
{
int left;
int right;
int number;
};
line lines[MAX<<2];
void buildTree(int le,int ri,int root)
{
lines[root].left=le;
lines[root].right=ri;
lines[root].number=0;
if(le==ri)
{
return ;
}
int mid=(le+ri)>>1;
buildTree(le,mid,root<<1);
buildTree(mid+1,ri,(root<<1)+1);
}
void insert(int le,int ri,int root)
{
if(lines[root].left==le&& lines[root].right==ri)
{
lines[root].number++;
return ;
}
int mid=(lines[root].left+lines[root].right)>>1;
if(ri<=mid)
{
insert(le,ri,root<<1);
}else
if(le>mid)
{
insert(le,ri,(root<<1)+1);
}else
{
insert(le,mid,root<<1);
insert(mid+1,ri,(root<<1)+1);
}
}
int query(int le,int ri,int root)
{
int sum=0;
if(lines[root].left==le&&lines[root].right==ri)
{
sum+=lines[root].number;
}
else
{
int mid=(lines[root].left+lines[root].right)>>1;
if(ri<=mid)
{
sum+=lines[root].number;
sum+=query(le,ri,root<<1);
}else
{
sum+=lines[root].number;
sum+=query(le,ri,(root<<1)+1);
}
}
return sum;
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
if(N==0)break;
int i,a,b;
buildTree(1,N,1);
for(i=1;i<=N;i++)
{
scanf("%d%d",&a,&b);
if(a<=b){insert(a,b,1);}
else
insert(b,a,1);
}
for(i=1;i<=N-1;i++)
{
printf("%d ",query(i,i,1));
}
printf("%d\n",query(N,N,1));
}
return 0;
}
有牛人用线性的方法做的,在此膜拜一下,顺便贴下代码
#include<stdio.h>
#include<string.h>
int hash[100002];
int main()
{
int n,i,x,y,sum;
while(scanf("%d",&n),n)
{
memset(hash,0,sizeof(hash));
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
hash[x]++;
hash[y+1]--;
}
printf("%d",hash[1]);
sum=hash[1];
for(i=2;i<=n;i++)
{
sum+=hash[i];
printf(" %d",sum);
}
printf("\n");
}
return 0;
}