http://poj.org/problem?id=2481
给出n个区间
输出每个区间 是多少个区间的真子集
思路:区间左端点为第一关键字,右端点第二关键字,前者升序后者降序
这样对每个区间i,只需要查询 Ri到n有多少个右端点就是答案, 可能有好几个区间相同,那么预处理一下最后减掉完全相同的区间即可
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const long long maxn = 100005; struct tree { int sum[maxn*4]; void init() { memset(sum,0,sizeof(sum)); } void pushup(int rt) { sum[rt]= (sum[rt<<1]+sum[rt<<1|1]); } void update(int l,int r,int num,int rt,int val) { if (l==r&&l==num ) { sum[rt]+=val; return ; } int mid=(l+r)/2; if (num<=mid) update(l,mid,num,rt<<1,val); else update(mid+1,r,num,rt<<1|1,val); pushup(rt); } int query(int ql,int qr,int l,int r,int rt) { if (ql<=l&&r<=qr) return sum[rt]; int mid=(l+r)>>1; int ret=0; if (ql<=mid) ret+= query(ql,qr,l,mid,rt<<1); if (qr>mid) ret+= query(ql,qr,mid+1,r,rt<<1|1); return ret; } }; tree tp; struct node { int l,r,id; int num; }; node tm[100005]; bool cmp(const node &a,const node &b) { if (a.l!=b.l) return a.l<b.l; else return a.r>b.r; } int ans[100005]; int main( ) { int i; int x; int n,h,w; int l,r; int cun=0; while(scanf("%d",&n)!=EOF) { if (!n) break; tp.init(); for (i=1; i<=n; i++) { scanf("%d %d",&l,&r); tm[i].l=l+1; tm[i].r=r+1; tm[i].id=i; } sort(tm+1,tm+1+n,cmp); for (i=n; i>=1; i--) { int j=i-1; while(tm[j].l==tm[i].l&&tm[j].r==tm[i].r &&j>=1) { j--; } int tol=i-j-1; tm[i].num=tol; } for (i=1; i<=n; i++) { // printf("tm[i].r :%d\n",tm[i].r-1); int ret=tp.query(tm[i].r,100001,1,100001,1); // printf("ret:%d\n",ret); //printf("num:%d\n",tm[i].num); if (ret>tm[i].num) ans[tm[i].id]=ret-tm[i].num; else ans[tm[i].id]=0; tp.update(1,100001,tm[i].r,1,1); } for (i=1; i<=n; i++) { if (i!=1) printf(" "); printf("%d",ans[i]); } printf("\n"); } return 0; }