bzoj 3262 陌上花开
作者:互联网
bzoj 3262 陌上花开
- \(CDQ\) 分治模板题.先将所有点按照 \(a\) 的大小排序,然后分治处理.
- 处理区间 \([l,r]\) 时,可以递归解决 \([l,mid],[mid+1,r]\) 两个区间内的贡献,于是只需要处理区间 \([l,mid]\) 对区间 \([mid+1,r]\) 的贡献.
- 把这些点全部按照 \(b\) 的大小排序,这样前两维都有序了.然后遍历一次.对于原来是左边的点,就在 \(c\) 的位置加 \(1\) ,原来是右边的点,就询问一次 \([1,c]\) 加了几次.用树状数组维护一下.
- 思路还是比较简单的?然而此题细节较多...
- 有三维全部相同的点.直接做的话,相同点彼此间贡献就会算漏.解决方法是在读入后手动去重,并且记录每个点的个数.这样修改的时候加的权值就为个数,最后统计答案的时候也要考虑相同的点个数.
- 一定要排全序,否则会算漏???
- 清空树状数组的时候别傻不拉几地 \(fill/memset\) ,正确姿势是把改过的地方记下来,结束的时候改回去.最大的几组数据常数大概差了 \(10\sim 30\) 倍?
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=1e5+10;
int T;
struct node
{
int a,b,c,id,cnt,f;
void init()
{
a=read(),b=read(),c=read();
cnt=1;
}
bool operator < (const node &rhs) const
{
if(T==1)
{
if(a!=rhs.a)
return a<rhs.a;
if(b!=rhs.b)
return b<rhs.b;
return c<rhs.c;
}
if(b!=rhs.b)
return b<rhs.b;
if(c!=rhs.c)
return c<rhs.c;
return a<rhs.a;
}
} q[MAXN],oq[MAXN];
int n,k;
int bit[MAXN<<1];
int ans[MAXN],times[MAXN];
#define lowbit(x) x&(-x)
void add(int x,int c)
{
for(; x<=k; x+=lowbit(x))
bit[x]+=c;
}
int query(int x)
{
int s=0;
for(; x; x-=lowbit(x))
s+=bit[x];
return s;
}
node Q[MAXN];
int tp,pos[MAXN],v[MAXN];
void solve(int l,int r)
{
if(l==r)
return;
int mid=(l+r)>>1;
solve(l,mid);
// fill(bit,bit+1+k,0);
tp=0;
int cnt=0;
for(int i=l; i<=r; ++i)
{
Q[++cnt]=q[i];
Q[cnt].f=(i<=mid)?1:0;
}
T=2;
sort(Q+1,Q+1+cnt);
for(int i=1; i<=cnt; ++i)
{
if(Q[i].f)
{
add(Q[i].c,Q[i].cnt);
++tp;
pos[tp]=Q[i].c,v[tp]=Q[i].cnt;
}
else
{
int id=Q[i].id;
ans[id]+=query(Q[i].c);
}
}
for(int i=1;i<=tp;++i)
add(pos[i],-v[i]);
solve(mid+1,r);
}
int tot[MAXN];
int main()
{
n=read(),k=read();
for(int i=1; i<=n; ++i)
oq[i].init();
T=1;
int N=n;
int rp=0;
sort(oq+1,oq+1+n);
int fst=0;
for(int i=1; i<=n; ++i)
{
if(i==1 || oq[i].a!=oq[i-1].a || oq[i].b!=oq[i-1].b || oq[i].c!=oq[i-1].c)
{
if(fst)
{
q[++rp]=oq[fst];
q[rp].id=rp;
times[rp]=q[rp].cnt;
}
fst=i;
}
else
++oq[fst].cnt;
}
q[++rp]=oq[fst],q[rp].id=rp;
times[rp]=q[rp].cnt;
n=rp;
solve(1,n);
for(int i=1; i<=n; ++i)
tot[ans[i]+times[i]-1]+=times[i];
for(int i=0; i<N; ++i)
printf("%d\n",tot[i]);
return 0;
}
标签:int,陌上,jp,mid,个数,3262,区间,bit,bzoj 来源: https://www.cnblogs.com/jklover/p/10593263.html