传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3262
题解:cdq分治可以写,树套树也可以;我写的是cdq分治:
做法:三维,然后这题正解是传统的cdq分治+排序+树状数组,设花的三个属性为x,y,z,我们将花按x为第一关键字,y为第二关键字,z为第三关键字排序,将属性完全相同的缩成一朵花即可,同时维护sum数组,即属形为(x,y,z)的个数,所以在维护树状数组的时候不能+1,而应该+sum[x]。排序后,后面的花只可能会被前面的花所影响,因为在该花后面的花x都比该花大,我们便能想到用cdq分治。
想到这点后,对于合并两个区间信息的问题,我们考虑两个区间分别按y坐标排序,依次第一个区间中的花将z坐标加入树状数组,并及时维护第二个区间中的花的答案,这过程用两个指针维护即可。
cdq分治+树状数组【oyzx神犇的博客转载,我不想打了。。。。。。】
树套树:x排序,y树状数组或者线段树维护,z平衡树维护。。。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 100005
using namespace std;
int n,m,tot,cnt;
int ans[N];
struct data{
int a,b,c,s,ans;
}q[N],a[N];
inline int read()
{
int x=
0,f=
1;
char ch=
getchar();
while(ch>
'9'||ch<
'0'){
if(ch==
'-')f=-
1;ch=
getchar();}
while(ch>=
'0'&&ch<=
'9'){x=x*
10+ch-
'0';ch=
getchar();}
return x*
f;
}
bool cmp(data a,data b)
{
if (a.a==b.a && a.b==b.b)
return a.c<
b.c;
if (a.a==b.a)
return a.b<
b.b;
return a.a<
b.a;
}
bool cmp2(data a,data b)
{
if (a.b==b.b)
return a.c<
b.c;
return a.b<
b.b;
}
struct Tbit{
int t[N*
2];
void modify(
int x,
int v){
for (
int p=x;p<=m;p+=p&-p) t[p]+=
v;}
int query(
int x){
int res=
0;
for (
int p=x;p;p-=p&-p) res+=t[p];
return res;}
}T;
void solve(
int l,
int r)
{
if (l==r)
return;
int mid=(l+r)>>
1;
solve(l,mid); solve(mid+
1,r);
sort(q+l,q+mid+
1,cmp2);
sort(q+mid+
1,q+r+
1,cmp2);
int i=l,j=mid+
1,last=
0;
while (j<=
r)
{
while (i<=mid && q[i].b<=
q[j].b)
{
T.modify(q[i].c,q[i].s);
i++
;
}
q[j].ans+=
T.query(q[j].c);
j++
;
}
for (
int j=l; j<i; j++) T.modify(q[j].c,-
q[j].s);
}
int main()
{
n=read(); m=
read();
for (
int i=
1; i<=n; i++) a[i].a=read(),a[i].b=read(),a[i].c=
read();
sort(a+
1,a+
1+
n,cmp);
cnt=
0;
for (
int i=
1; i<=n; i++
)
{
cnt++
;
if (a[i].a!=a[i+
1].a || a[i].b!=a[i+
1].b || a[i].c!=a[i+
1].c)
{
q[++tot]=a[i]; q[tot].s=cnt; cnt=
0;
}
}
solve(1,tot);
for (
int i=
1; i<=tot; i++) ans[q[i].ans+q[i].s-
1]+=
q[i].s;
for (
int i=
0; i<n; i++) printf(
"%d\n",ans[i]);
}
View Code
转载请注明原文地址: https://ju.6miu.com/read-1301345.html