Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
Input
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。
以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性
Output
包含N行,分别表示评级为0…N-1的每级花的数量
Sample Input
10 3 3 3 3 2 3 3 2 3 1 3 1 1 3 1 2 1 3 1 1 1 2 1 2 2 1 3 2 1 2 1
Sample Output
3 1 3 0 1 0 1 0 0 1
因为这段时间一直在写KDtree,突发奇想写了个三维偏序,原地爆炸。
一维排序+方差划分+离线操作,洛谷上会十分华丽的T成60分。但是BZOJ是可以卡线的。
虽然用cdqAC才是正常操作,但KDtree二维+一维排序仍然是一种思路,
KDtree:
#include<cstdio> #include<algorithm> #define max(a,b) a>b?a:b #define abs(a) a>0?a:-a; #define pow(a) a*a; using namespace std; const int maxn=2e6+100; const int inf=0x3f3f3f3f; int ans[maxn]; int rid[maxn]; int n; int read(){ char c;int ret=0; c=getchar(); while(c>'9' || c<'0') c=getchar(); while(c>='0' && c<='9') ret=ret*10+c-'0',c=getchar(); return ret; } namespace KD_tree{ struct node{ int ch[2],mn[2],mx[2],pos[3],exist,d,fa,id,sum,rank; node(){mn[0]=mn[1]=inf;} void init(){sum=exist=1;for(int i=0;i<2;i++) mn[i]=mx[i]=pos[i];} }tree[maxn]; int D,cnt,root; inline bool operator <(const node &a,const node &b){ return a.pos[D]<b.pos[D]; } inline void push_up(int rt){ tree[rt].sum=tree[tree[rt].ch[0]].sum+tree[tree[rt].ch[1]].sum+tree[rt].exist; for(int i=0;i<2;i++) for(int j=0;j<2;j++){ tree[rt].mn[j]=min(tree[tree[rt].ch[i]].mn[j],tree[rt].mn[j]); tree[rt].mx[j]=max(tree[tree[rt].ch[i]].mx[j],tree[rt].mx[j]); } } inline long long Variance(int l,int r,bool type){ long long a=0,b=0,n=(r-l+1); for(int i=l;i<=r;i++){ a+=1LL*pow(tree[i].pos[type]); b+=1LL*tree[i].pos[type]; } return a/n-pow(b/n); } inline bool judge(int l,int r){ long long _x=0,_y=0; _x=Variance(l,r,0); _y=Variance(l,r,1); return _x<_y; } void build(int &rt,int l,int r,int fa){ if(l==r){rt=r;tree[rt].fa=fa;return ;} int mid=(l+r)/2;D=judge(l,r); nth_element(tree+l,tree+mid,tree+r+1); rt=mid;tree[rt].d=D;tree[rt].fa=fa; if(l<mid) build(tree[rt].ch[0],l,mid-1,rt); if(r>mid) build(tree[rt].ch[1],mid+1,r,rt); push_up(rt); } inline void insert(int w){ tree[w].init(); while(w) push_up(w),w=tree[w].fa; } inline bool in(int * mn,int * mx,node rect){ return mn[0]<=rect.mn[0] && mn[1]<=rect.mn[1] && mx[0]>=rect.mx[0] && mx[1]>=rect.mx[1]; } inline bool intsect(int * mn,int * mx,node rect){ return (max(mn[0],rect.mn[0])<=min(mx[0],rect.mx[0]))&&(max(mn[1],rect.mn[1])<=min(mx[1],rect.mx[1])); } inline bool pos_in(int x,int y,int * mn,int * mx){ return (x<=mx[0] && x>=mn[0] && y<=mx[1] && y>=mn[1]); } int query(int rt,int * mn,int * mx){ if(in(mn,mx,tree[rt])) return tree[rt].sum; if(intsect(mn,mx,tree[rt])){ int ret=0; if(tree[rt].ch[0]) ret+=query(tree[rt].ch[0],mn,mx); if(tree[rt].ch[1]) ret+=query(tree[rt].ch[1],mn,mx); return pos_in(tree[rt].pos[0],tree[rt].pos[1],mn,mx)&&tree[rt].exist?ret+1:ret; }else return 0; } } inline bool cmp(const KD_tree::node &a,const KD_tree::node &b){ return a.pos[2]==b.pos[2]?(a.pos[0]==b.pos[0]?a.pos[1]<b.pos[1]:a.pos[0]<b.pos[0]):a.pos[2]<b.pos[2]; } inline bool equ(KD_tree::node a,KD_tree::node b){ for(int i=0;i<3;i++) if(a.pos[i]!=b.pos[i]) return 0; return 1; } int main(){ using namespace KD_tree; n=read();read(); for(int i=1;i<=n;i++){ tree[i].pos[2]=read(); tree[i].pos[0]=read(); tree[i].pos[1]=read(); tree[i].id=i; } sort(tree+1,tree+n+1,cmp); for(int i=1;i<=n;i++) tree[i].rank=i; build(root,1,n,0); for(int i=1;i<=n;i++) rid[tree[i].rank]=i; for(int i=1;i<=n;i++){ int cnt=1; while(equ(tree[rid[i]],tree[rid[i+1]])){ insert(rid[i++]); cnt++; } int w=rid[i]; insert(w); int mn[]={0,0}; int mx[]={tree[w].pos[0],tree[w].pos[1]}; int t=query(root,mn,mx); ans[t-1]+=cnt; } for(int i=0;i<n;i++) printf("%d\n",ans[i]); return 0; }
CDQ:
#include<cstdio> #include<cctype> #include<algorithm> using namespace std; const int maxn = 1e5 + 5; struct point { int x, y, z, pos, id, cnt; }rp[maxn], p[maxn], mg[maxn]; int n, k, a, b, c, ans[maxn], sum[maxn], cnt; int mcnt, pl, pr; inline char gc(){ static char buf[5000000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 5000000, stdin), p1 == p2) ? EOF : *p1++; } inline void read(int & x) { x = 0;static char c = gc(); while(!isdigit(c)) c = gc(); while(isdigit(c)) x = x * 10 + c - '0', c = gc(); } void write(int x) { if(x / 10) write(x / 10); putchar(x % 10 + '0'); } bool cmp_xyz(const point &a, const point &b) { return a.x == b.x ? (a.y == b.y ? (a.z < b.z) : a.y < b.y) : a.x < b.x; } inline bool cmp_yzx(const point &a, const point &b) { return a.y == b.y ? (a.z == b.z ? (a.x < b.x) : a.z < b.z) : a.y < b.y; } namespace BIT { int tree[maxn << 1]; #define lowbit(x) ((x) & (-(x))) void add(int x, int p) {while(x <= k) tree[x] += p, x += lowbit(x);} int query(int x) { int ans = 0; while(x) ans += tree[x], x -= lowbit(x); return ans; } } void cdq(int l, int r) { if(l == r) return; int mid = l + r >> 1; cdq(l, mid), cdq(mid + 1, r); mcnt = 0, pl = l, pr = mid + 1; while(pl <= mid && pr <= r) if(cmp_yzx(p[pl], p[pr])) mg[++mcnt] = p[pl++]; else mg[++mcnt] = p[pr++]; while(pl <= mid) mg[++mcnt] = p[pl++]; while(pr <= r) mg[++mcnt] = p[pr++]; for(register int i = 1; i <= mcnt; ++i) p[l + i - 1] = mg[i]; for(register int i = l; i <= r; ++i) { if(p[i].id <= mid) BIT::add(p[i].z, p[i].cnt); else ans[p[i].pos] += BIT::query(p[i].z); } for(register int i = l; i <= r; ++i) if(p[i].id <= mid) BIT::add(p[i].z, -p[i].cnt); } int main() { read(n), read(k); for(register int i = 1; i <= n; ++i) { read(a), read(b), read(c); rp[i] = (point) {a, b, c, i, 0, 1}; } sort(rp + 1, rp + n + 1, cmp_xyz); for(register int i = 1; i <= n; ++i) { if(rp[i].x == rp[i - 1].x && rp[i].y == rp[i - 1].y && rp[i].z == rp[i - 1].z) ++p[cnt].cnt; else p[++cnt] = rp[i], p[cnt].id = cnt; } cdq(1, cnt); for(register int i = 1; i <= cnt; ++i) sum[ans[p[i].pos] + p[i].cnt - 1] += p[i].cnt; for(register int i = 0; i < n; ++i) write(sum[i]), putchar('\n'); return 0; }
没有帐号? 立即注册