这道杭电题以前有点不懂,但是现在懂了。。终于懂了。。附代码,三种方法哦!!!呵呵呵;见代码吧!!具体问题见代码分析!!
方法一:(也是做容易想到的,线段树。)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=111111;
int sum,root[N<<2];
int n;
void update(int l,int r,int rt,int x,int y)
{
if(x<=l&&y>=r)
{
root[rt]++;
return ;
}
int m=(l+r)>>1;
if(x>m) update(m+1,r,rt*2+1,x,y);//实际这几个if else语句可以转化为:/*if(x<=m) query(l,m,rt*2,x,y);else if(y>m) query(m+1,r,rt*2+1,x,y);*/
else if(y<=m) update(l,m,rt*2,x,y);// 这样更易理解,,,
else
{
update(l,m,rt*2,x,y);
update(m+1,r,rt*2+1,x,y);
}
}
void query(int l,int r,int rt,int sum)
{
if(l==r)
{
printf("%d%c",sum+root[rt],l==n?'\n':' ');
return ;
}
int m=(l+r)>>1;
query(l,m,rt*2,sum+root[rt]);
query(m+1,r,rt*2+1,sum+root[rt]);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0)break;
memset(root,0,sizeof(root));
int x,y;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
update(1,n,1,x,y);
}
query(1,n,1,0);
}
return 0;
}
方法二:(也是利用线段树,加上了结构体,可能理解上会有点难。)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef struct n
{
int l;
int r;
int color;
} T;
T tree[500000];
int flag[100010];
void make_tree(int l,int r,int rt )
{
//if(tree[rt].l==tree[rt].r)
// {
// return ;
// }
tree[rt].l=l;
tree[rt].r=r;
tree[rt].color=0;
if(l!=r)
{
int m=(l+r)>>1;
make_tree(l,m,rt*2);
make_tree(m+1,r,rt*2+1);
}
}
void update(int l,int r,int rt)
{
if(l<=tree[rt].l&&r>=tree[rt].r)
{
tree[rt].color++;
return ;
}
else
{
int m=(tree[rt].l+tree[rt].r)>>1;
if(l>m)
update(l,r,rt*2+1);
else
{
if(r<=m)
update(l,r,rt*2);
else
{
update(l,m,rt*2);
update(m+1,r,rt*2+1);
}
}
}
}
void count(int x)
{
if(tree[x].l==tree[x].r)
{
flag[tree[x].l]=tree[x].color;
return ;
}
tree[2*x].color+=tree[x].color;
tree[2*x+1].color+=tree[x].color;
count(2*x);
count(2*x+1);
}
int main()
{
int i,n;
while(scanf("%d",&n)!=EOF&&n)
{
make_tree(1,n,1);
int x,y;
for(i=1; i<=n; i++)
{
scanf("%d%d",&x,&y);
update(x,y,1);
}
memset(flag,0,sizeof(flag));
count(1);
for(i=1; i<n; i++)
// {
printf("%d ",flag[i]);
// if(i==n-1)
printf("%d\n",flag[i]);
// }
}
return 0;
}
方法三(利用数组解决,但是这里有个小技巧要注意下,否则在一般情况下会超时。。)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
int i,n,a,b;
int f[100005];
while(scanf("%d",&n)!=EOF&&n)
{
memset(f,0,sizeof(f));
for(i=0;i<n;i++)
{
scanf("%d%d",&a,&b); 需要注意的就是这里,一下就是小技巧。
f[a]++; //并不是把每一个的更新的区间每一个数都变化,显然那样会超时,那是绝对的,所以就直接对一头一尾的数进行处理,这样每一个数都和前一个数有关。但
//但是还有就是在最后一个数时,必须向后移动一位,这个技巧自己慢慢领会。且最后一个数是减1的。
f[b+1]--;
}
for(i=1;i<=n;i++)
{
f[i]+=f[i-1]; //这里也是需要注意的,因为在前面,不是一头的数加了1吗!!所以更具有点dp的思想,进行加。这样就是每一个数都和它前一个数有关。
if(i>1)cout<<' ';
cout<<f[i];
}
cout<<endl;
}
return 0;
}