Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 15187 | Accepted: 5054 |
Description
Input
Output
Sample Input
3 1 2 0 3 3 4 0
Sample Output
1 0 0
Hint
Source
首先将所有区间按右端点从大到小排序,依次把每个点左端点的权值加1,并统计1到左端点所有权值的和作为答案。注意两个区间相同的情况。
于是问题转化为单点修改和区间求和,树状数组解决。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define LL long long #define pa pair<int,int> #define MAXN 200005 using namespace std; struct data { int l,r,num; }a[MAXN]; int n,mx,f[MAXN],ans[MAXN]; int read() { int ret=0,flag=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();} while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();} return ret*flag; } bool cmp(data x,data y) { if (x.r!=y.r) return x.r>y.r; else return x.l<y.l; } void update(int k) { for(int i=k;i<=mx;i+=(i&(-i))) f[i]++; } int getsum(int k) { int ret=0; for(int i=k;i;i-=(i&(-i))) ret+=f[i]; return ret; } int main() { scanf("%d",&n); while (n) { mx=0; int tmp=0; memset(f,0,sizeof(f)); F(i,1,n) a[i].num=i,a[i].l=read()+1,a[i].r=read()+1,mx=max(mx,a[i].r); sort(a+1,a+n+1,cmp); F(i,1,n) { if (a[i].l==a[i-1].l&&a[i].r==a[i-1].r) tmp++; else tmp=1; update(a[i].l); ans[a[i].num]=getsum(a[i].l)-tmp; } F(i,1,n-1) printf("%d ",ans[i]); printf("%d\n",ans[n]); scanf("%d",&n); } }