bzoj 3262 陌上花开

bzoj 3262 陌上花开

  • \(CDQ\) 分治模板题.先将所有点按照 \(a\) 的大小排序,然后分治处理.
  • 处理区间 \([l,r]\) 时,可以递归解决 \([l,mid],[mid+1,r]\) 两个区间内的贡献,于是只需要处理区间 \([l,mid]\) 对区间 \([mid+1,r]\) 的贡献.
  • 把这些点全部按照 \(b\) 的大小排序,这样前两维都有序了.然后遍历一次.对于原来是左边的点,就在 \(c\) 的位置加 \(1\) ,原来是右边的点,就询问一次 \([1,c]\) 加了几次.用树状数组维护一下.
  • 思路还是比较简单的?然而此题细节较多...
  1. 有三维全部相同的点.直接做的话,相同点彼此间贡献就会算漏.解决方法是在读入后手动去重,并且记录每个点的个数.这样修改的时候加的权值就为个数,最后统计答案的时候也要考虑相同的点个数.
  2. 一定要排全序,否则会算漏???
  3. 清空树状数组的时候别傻不拉几地 \(fill/memset\) ,正确姿势是把改过的地方记下来,结束的时候改回去.最大的几组数据常数大概差了 \(10\sim 30\) 倍?

\(upd:\) 每次都直接清空复杂度都是假的...我咋这么弱智...

#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;
}
posted @ 2019-03-25 13:37  jklover  阅读(104)  评论(0编辑  收藏  举报