CDQ分治

首先,偏序是什么

一维偏序就是数列中对于每个(x)有多少个(aleq x)

二维偏序就是二元组((x,y))有多少((a,b))满足(aleq x wedge bleq y)

...

一维偏序可以直接排序

二维偏序联想到逆序对可以给第一位排序第二维数据结构

三维偏序第一维排序第二维cdq分治第三维树状数组

其实二维还有一个方法就是归并排序

每次二分时顺便统计左边对右边的影响

cdq分治就是这样

没了。。??

update kdtree txdy!

陌上花开

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 300001
using namespace std;

int n,m,k,a[M],c[M],cnt[M];
struct vv {	int a,b,c,id,num,ans;} d[M],tmp[M];
bool cmp(vv a,vv b) 
{
	if(a.a!=b.a) return a.a<b.a;
	if(a.b!=b.b) return a.b<b.b;
	return a.c<b.c;
}

void add(int x,int k) { for(int i=x;i<=m;i+=i & -i) c[i]+=k;}
int ask(int x) { int ans=0; for(int i=x;i>0;i-=i & -i) ans+=c[i]; return ans;}

void cdq(int l,int r)
{
	if(l==r) return ;
	int mid=(l+r)>>1,cnt=0, j=l;
	cdq(l,mid); cdq(mid+1,r);
	for(int i=mid+1;i<=r;i++)
	{
		while(d[j].b<=d[i].b && j<=mid) add(d[j].c,d[j].num), tmp[cnt++]=d[j++];
		d[i].ans+=ask(d[i].c); tmp[cnt++]=d[i];  
	}
	for(int i=l;i<j;i++) add(d[i].c,-d[i].num);
	for(int i=mid;i>=j;i--) d[r+i-mid]=d[i]; 
	for(int i=0;i<cnt;i++) d[l+i]=tmp[i];
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d%d%d",&tmp[i].a,&tmp[i].b,&tmp[i].c), tmp[i].num=1;
	sort(tmp+1,tmp+1+n,cmp); 
	for(int i=1;i<=n;i++)
		if(tmp[i].a!=tmp[i-1].a || tmp[i].b!=tmp[i-1].b || tmp[i].c!=tmp[i-1].c) d[++k]=tmp[i], d[k].id=k;
		else d[k].num+=1;
	cdq(1,k); 
	for(int i=1;i<=k;i++) cnt[d[i].ans+d[i].num-1]+=d[i].num;
	for(int i=0;i<n;i++) printf("%d
",cnt[i]);
}

这辈子都学不会斜率优化了

[USACO07JAN]Cow School G

考虑前k大的数的答案是(frac{sum_{i=1}^k a_i}{sum_{i=1}^k b_i}=frac A B)

移向就是(sum_{i=1}^k Ba_i-Ab_i=0), 可以观察到如果有另一个集合的和大于0的话那么前k大就不是最优答案

换句话说就是找到不在前k大里的最大的(Ba_x-Ab_x)和前k大里最小的(Ba_y-Ab_y)如果有前一个大于后一个,那么上面的式子就会大于零,也就是找到了一个比选前k个要优的答案

再观察这个式子(Ba_x-Ab_x=C)(frac B A a_x-frac C A=b_x)要求最大/最小化(frac C A)这里就是斜率优化

然而斜率优化和cdq分治都是我这辈子学不会的东西

ctz_tttttttttttttttttttttttttttttql!!!!!!!!!!!!!!!!!!!!!!

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;

const int M = 200001;
int n,m,k,tp,tl,A[M],B[M];
double ansx[M],ansn[M];
struct vv 
{
	int id,x,y,tag;
} d[M],tmp[M];

struct pt
{
	int x,y;
} st[M],a[M];

pt operator - (const pt&a,const pt&b) {return {a.x-b.x,a.y-b.y}; }

double operator ^ (const pt&a,const pt&b){return 1.0*a.x*b.y-1.0*a.y*b.x;}

void ins(int x,int y,int k)
{
	while(tp>tl &&((st[tp-1]-st[tp])^((pt){x,y}-st[tp]))*k<0) tp--;
	st[++tp]={x,y};
}

double ask(double k,pt a)
{
	return k*a.x-a.y;
}

void pp(double k,int tg)
{
	while(tp>tl && (ask(k,st[tl])*tg<ask(k,st[tl+1])*tg)) tl++;
}

bool cmp(vv a,vv b,int k)
{
	if(a.tag!=b.tag) return a.tag<b.tag;
	if(a.tag==0)
	{
		if(a.x<b.x || (a.x==b.x && k*a.y>k*b.y)) return 1;
		return 0;
	}
	return 1.0*a.x/a.y*k>1.0*b.x/b.y*k;
}

void cdq1(int l,int r)
{
	if(l==r) return; 
	int mid=(l+r)>>1;
	cdq1(l,mid); cdq1(mid+1,r);
	tp=0, tl=1;
	for(int i=l;i<=mid;i++) if(!d[i].tag) ins(d[i].x,d[i].y,-1);
	for(int i=mid+1;i<=r;i++) if(d[i].tag)
	{

		pp(1.0*d[i].x/d[i].y,1);
		if(tp>=tl) ansx[d[i].id]=max(ansx[d[i].id],ask(1.0*d[i].x/d[i].y,st[tl]));
	} 
	
	int Tl=l,Tr=mid+1, t=0;
	while(Tl<=mid && Tr<=r)
	{
		if(cmp(d[Tl],d[Tr],-1))  tmp[++t]=d[Tl++];
		else tmp[++t]=d[Tr++];
	}
	while(Tl<=mid) tmp[++t]=d[Tl++];
	while(Tr<=r) tmp[++t]=d[Tr++];
	for(int i=1;i<=t;i++) d[l+i-1]=tmp[i];
}

void cdq2(int l,int r)
{
	if(l==r) return; 
	int mid=(l+r)>>1;
	cdq2(l,mid); cdq2(mid+1,r);
	tp=0, tl=1;
	for(int i=l;i<=mid;i++) if(!d[i].tag) ins(d[i].x,d[i].y,1);
	for(int i=mid+1;i<=r;i++) if(d[i].tag)
	{
		pp(1.0*d[i].x/d[i].y,-1);
		if(tp>=tl) ansn[d[i].id]=min(ansn[d[i].id],ask(1.0*d[i].x/d[i].y,st[tl]));
	} 
	
	int Tl=l,Tr=mid+1, t=0;
	while(Tl<=mid && Tr<=r)
	{
		if(cmp(d[Tl],d[Tr],1))  tmp[++t]=d[Tl++];
		else tmp[++t]=d[Tr++];
	}
	while(Tl<=mid) tmp[++t]=d[Tl++];
	while(Tr<=r) tmp[++t]=d[Tr++];
	for(int i=1;i<=t;i++) d[l+i-1]=tmp[i];
}

bool Cmp(pt a,pt b) {return 1.0*a.x/a.y>1.0*b.x/b.y;}
bool Cmp_(pt a,pt b) {return 1.0*a.x/a.y<1.0*b.x/b.y;}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
	}
	sort(a+1,a+1+n,Cmp); int t=0;
	for(int i=1;i<=n;i++)
	{
		t++;
		d[t].id=i, d[t].x=a[i].x, d[t].y=a[i].y, d[t].tag=0;
		t++;
		A[i]=A[i-1]+a[i].x, B[i]=B[i-1]+a[i].y;
		d[t].id=i; d[t].y=A[i], d[t].x=B[i], d[t].tag=1;
		ansn[i]=1e10;
	}
	cdq2(1,t); sort(a+1,a+1+n,Cmp_);
	t=0;
	for(int i=1;i<=n;i++)
	{
		if(i>1)t++;
		if(i>1)d[t].id=i-1, d[t].y=A[n-i+1], d[t].x=B[n-i+1], d[t].tag=1;
		t++;
		d[t].id=i, d[t].x=a[i].x, d[t].y=a[i].y, d[t].tag=0;
		ansx[i]=-0x3f3f3f3f;
	}

	cdq1(1,t);
	int sm=0; 
	for(int i=n-1;i>=1;i--)	if(ansn[i]<ansx[n-i]) A[++sm]=n-i;
	printf("%d
",sm);
	for(int i=1;i<=sm;i++) printf("%d
",A[i]);
}
原文地址:https://www.cnblogs.com/ZUTTER/p/10383590.html