cdq分治专题

cdq分治是一种往往用于多维偏序问题的算法

比如n维问题

一维先排好所有子问题,然后solve(l,mid),solve(mid+1,r),之后按照第二维排序[l,r],处理[l,mid]对[mid+1,r]的影响,影响通过一个n-2维的数据结构来体现

复杂度:n*logn*数据结构复杂度

这样我们便用cdq分治优化掉了一维


bzoj3262

标准的三位偏序问题。。。写的第一道cdq分治,按照对cdq分治的理解与归并排序的实现自己意淫出来的写法,没想到竟然过了。。。

#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
int n,k;
struct flower
{
	int s,c,m;
	int num;
	int ans;
}hua1[100050],hua2[100050];
int cmp(flower a,flower b)
{
	if(a.s==b.s&&a.c==b.c)
		return a.m<b.m;
	if(a.s==b.s)
		return a.c<b.c;
	return a.s<b.s;
}
int cmp2(flower a,flower b)
{
	if(a.c==b.c)
		return a.m<b.m;
	return a.c<b.c;
}
int in[200050];
int lowbit(int x)
{
	return x&(-x);
}
void plu(int pos,int num)
{
	while(pos<=k)
	{
		in[pos]+=num;
		pos+=lowbit(pos);
	}
}
int sum(int end)
{
	int res=0;
	while(end>0)
	{
		res+=in[end];
		end-=lowbit(end);
	}
	return res;
}
void solve(int l,int r)
{
	if(l==r)
		return ;
	int mid=(l+r)/2;
	solve(l,mid);
	solve(mid+1,r);
	sort(hua2+l,hua2+mid+1,cmp2);
	sort(hua2+mid+1,hua2+r+1,cmp2);
	int i=l,j=mid+1;
	while(j<=r)
	{
//		if(l==6&&r==10)
//			cout<<i<<" "<<j<<endl,cout<<hua[i].c<<" "<<hua[j].c<<endl;
		while(hua2[i].c<=hua2[j].c&&i<=mid)
		{
		//	if(l==6&&r==10)
		//	cout<<" .. "<<hua[i].s<<" "<<hua[i].c<<" "<<hua[i].m<<" "<<hua[i].num<<endl;
			plu(hua2[i].m,hua2[i].num);
			i++;
		}
		hua2[j].ans+=sum(hua2[j].m);
	//	if(l==6&&r==10)
	//		cout<<sum(hua[j].m)<<" "<<hua[j].s<<" "<<hua[j].c<<" "<<hua[j].m<<" "<<hua[j].ans<<endl;
		j++;
	}
	for(int yu=l;yu<i;yu++)
		plu(hua2[yu].m,-hua2[yu].num);
}
int ans[100050];
int main()
{
	int cnt=0;
	cin>>n>>k;
	int a,b,c;
	for(int i=1;i<=n;i++)
		scanf("%d%d%d",&hua1[i].s,&hua1[i].c,&hua1[i].m);
	sort(hua1+1,hua1+n+1,cmp);
	int jk=0;
	for(int i=1;i<=n;i++)
	{
		jk++; 
		if(hua1[i].s!=hua1[i+1].s||hua1[i].c!=hua1[i+1].c||hua1[i].m!=hua1[i+1].m)
			hua2[++cnt]=hua1[i],hua2[cnt].num=jk,jk=0;
	}
	solve(1,cnt);
	for(int i=1;i<=cnt;i++)
		ans[hua2[i].ans+hua2[i].num-1]+=hua2[i].num;
	   for(int i=0;i<n;i++)
        printf("%d\n",ans[i]);
} 


bzoj1176=bzoj4066

这里注意cmp的写法,如果不考虑x相等时按原序排是会wa的TAT

#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int N=2000050;
int c[N];
int s,w;
int lowbit(int x)
{
	return x&(-x);
}
void plu(int pos,int x)
{
	if(pos==0)
		return;
	while(pos<=w)
		c[pos]+=x,pos+=lowbit(pos);
}
int get(int end)
{
	int sum=0;
	while(end>0)
		sum+=c[end],end-=lowbit(end);
	return sum;
}
struct que
{
	int l,r,x,lei1,pos,lei2,aim;
}q[N];
int cmp(que a,que b)
{	
	if(a.x==b.x)
		return a.pos<b.pos;
	return a.x<b.x;
}
int ans[N],cnt1,cnt;
void solve(int l,int r)
{
	if(l==r)
		return ;
	int mid=(l+r)/2;
	solve(l,mid);
	solve(mid+1,r);
	sort(q+l,q+r+1,cmp);
	for(int i=l;i<=r;i++)
	{
		if(q[i].lei1==1&&q[i].pos<=mid)
			plu(q[i].l,q[i].lei2);
		else if(q[i].lei1==2&&q[i].pos>mid)
			ans[q[i].aim]+=q[i].lei2*(get(q[i].r)-get(q[i].l-1));
	}
	for(int i=l;i<=r;i++)
		if(q[i].lei1==1&&q[i].pos<=mid)
			plu(q[i].l,-q[i].lei2);
}
int lei;
int x,xx,y,yy,vl;
bool vis[N];
int f;
int main()
{
	scanf("%d%d",&s,&w);
	while(scanf("%d",&lei)==1)
	{
		if(lei==3)
			break;
		cnt++;
		if(lei==1)
		{
			scanf("%d%d%d",&x,&y,&vl);
			q[++cnt1].pos=cnt1;
			q[cnt1].x=x;
			q[cnt1].l=y;
			q[cnt1].lei2=vl;
			q[cnt1].lei1=1;
		}
		else
		{
			scanf("%d%d%d%d",&x,&y,&xx,&yy);
			q[++cnt1].pos=cnt1;
			q[cnt1].aim=++f;
			q[cnt1].x=x-1;
			q[cnt1].l=y;
			q[cnt1].r=yy;
			q[cnt1].lei1=2;
			q[cnt1].lei2=-1;
			q[++cnt1].pos=cnt1;
			q[cnt1].aim=f;
			q[cnt1].x=xx;
			q[cnt1].r=yy;
			q[cnt1].l=y;
			q[cnt1].lei1=2;
			q[cnt1].lei2=1;
		}
	}
	solve(1,cnt1);
	for(int i=1;i<=f;i++)
			printf("%d\n",ans[i]);
			
}


bzoj3963

斜率优化dp+cdq分治

很不错的题目,因为不满足单调性只好使用cdq来做,然而我推的斜率式将负号归在了另一边,导致单调性判断与斜率式恰好都与题解是反的。。以为殊途同归,然而一些点答案还是挂了。。只好按照题解的写法写了。。。

#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int N=100050;
struct machine
{
	long long get,sell,day,buy;
}m[N];
int cas,n,d;
long long dp[N];
long long geth(int num)
{
	return dp[num]+m[num].sell-m[num].buy-m[num].get*(m[num].day+1);
}
int q[N];
struct calc
{
	long long h,ge;
}A[N];
int cmp(calc a,calc b) 
{
	if(a.ge==b.ge)
		return a.h<b.h;
	return a.ge<b.ge;
}
int compar(calc a,calc b,calc c)
{
	long long xa=b.ge-a.ge;
	long long xb=c.ge-a.ge;
	long long ya=b.h-a.h;
	long long yb=c.h-a.h;
	double tmp=(double)xa*yb-(double)xb*ya;
	return tmp<0;
}
void solve(int l,int r)
{
	if(l>=r)
		return ;
	int mid=(l+r)/2;
	solve(l,mid);
	int head=0,tail=0,cnt=0;
	for(int i=l;i<=mid;i++)
		if(dp[i]>=m[i].buy)
			A[++cnt].h=geth(i),A[cnt].ge=m[i].get;
	sort(A+1,A+cnt+1,cmp);
	for(int i=1;i<=cnt;i++)
	{
		while(tail>1&&!compar(A[q[tail-1]],A[q[tail]],A[i]))
			tail--;
		q[++tail]=i;
	}
	for(int i=mid+1;i<=r;i++)
	{
		long long x=m[i].day;
		long long a1,a2,b1,b2;
		while(head<tail)
		{
			a1=A[q[head]].ge,a2=A[q[head+1]].ge;
			b1=A[q[head]].h,b2=A[q[head+1]].h;
			if(a1*x+b1>=a2*x+b2)
				break;
			head++;
		}
		dp[i]=max(dp[i],A[q[head]].ge*x+A[q[head]].h);
	}
	solve(mid+1,r);
}
long long D;
int cmp2(machine a,machine b)
{
	return a.day<b.day;
}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	while(1)
	{
		scanf("%d%lld%lld",&n,&dp[0],&D);
		if(!n)	break;
		for(int i=1;i<=n;i++)
			scanf("%lld%lld%lld%lld",&m[i].day,&m[i].buy,&m[i].sell,&m[i].get);
		sort(m+1,m+n+1,cmp2);
		m[++n].day=D+1,m[n].buy=m[n].get=m[n].sell=0;
		for(int i=1;i<=n;i++)	
			dp[i]=dp[0];
		solve(0,n);
		printf("Case %d: %lld\n",++cas,dp[n]);
	}
}


bzoj2716

也是很经典的题目,然而始终T。。。。QAQ。。。

找oj要了数据,自己测了30s-,然而交上去就是过不了。。。强行把锅推给bzojQWQ

话说把别人的题解交上去也是T。。。我就这么非吗。。。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=1000050;
int shangjie=0,n,m;
int c1[1000050],c2[1000050];
inline int getc() {    
    static const int L = 1 << 15;    
    static char buf[L], *S = buf, *T = buf;    
    if (S == T) {    
        T = (S = buf) + fread(buf, 1, L, stdin);    
        if (S == T)    
            return EOF;    
    }    
    return *S++;    
}    
inline int getint() {    
    int c;    
    while(!isdigit(c = getc()) && c != '-');    
    bool sign = c == '-';    
    int tmp = sign ? 0 : c - '0';    
    while(isdigit(c = getc()))    
        tmp = (tmp << 1) + (tmp << 3) + c - '0';    
    return sign ? -tmp : tmp;    
}    

int lowbit(int x)
{
	return x&(-x);
}
void plu(int pos,int x)
{
	while(pos<=shangjie)
		c1[pos]=max(x,c1[pos]),pos+=lowbit(pos);
}
void clear(int pos)
{
	while(pos<=shangjie)
		c1[pos]=-INF,pos+=lowbit(pos);
}
int maxx1(int end)
{
	int maxx=-0x3f3f3f3f;
	while(end>0)
		maxx=max(maxx,c1[end]),end-=lowbit(end);
	return maxx;
}
void plu2(int pos,int x)
{
	while(pos>0)
		c2[pos]=max(x,c2[pos]),pos-=lowbit(pos);
}
void clear2(int pos)
{
	while(pos>0)
		c2[pos]=-INF,pos-=lowbit(pos);
}
int maxx2(int end)
{
	int maxx=-0x3f3f3f3f;
	while(end<=shangjie)
		maxx=max(maxx,c2[end]),end+=lowbit(end);
	return maxx;
}
struct ope
{
	int lei,x,y,pos,aim;
}q1[N],q2[N];
int ans[N];
int cmp1(ope a,ope b)
{
	if(a.x==b.x)
		return a.pos<b.pos;
	return a.x<b.x;
}
int cmp2(ope a,ope b)
{
	if(a.x==b.x)
		return a.pos<b.pos;
	return a.x>b.x;
}
void solve1(int l,int r)
{
	if(l==r)
		return;
	int mid=(l+r)/2;
	solve1(l,mid);
	solve1(mid+1,r);
	sort(q1+l,q1+r+1,cmp1);
	for(int i=l;i<=r;i++)
	{
		if(q1[i].pos<=mid&&q1[i].lei==1)
			plu(q1[i].y,q1[i].x+q1[i].y),plu2(q1[i].y,q1[i].x-q1[i].y);
		else if(q1[i].pos>mid&&q1[i].lei==2)
			ans[q1[i].aim]=min(ans[q1[i].aim],q1[i].x+q1[i].y-maxx1(q1[i].y)),ans[q1[i].aim]=min(ans[q1[i].aim],q1[i].x-q1[i].y-maxx2(q1[i].y));
	}
	for(int i=l;i<=r;i++)
		if(q1[i].pos<=mid&&q1[i].lei==1)
			clear(q1[i].y),clear2(q1[i].y);
}
void solve2(int l,int r)
{
	if(l==r)
		return;
	//cout<<l<<" "<<r<<endl;
	int mid=(l+r)/2;
	solve2(l,mid);
	solve2(mid+1,r);
	sort(q2+l,q2+r+1,cmp2);
//	cout<<l<<" "<<r<<endl;
//	cout<<mid<<endl;
	for(int i=l;i<=r;i++)
	{
	//	cout<<q2[i].lei<<":"<<q2[i].x<<" "<<q2[i].y<<" "<<q2[i].pos<<" "<<q2[i].aim<<endl;
		if(q2[i].pos<=mid&&q2[i].lei==1)
			plu(q2[i].y,-q2[i].x+q2[i].y),plu2(q2[i].y,-q2[i].x-q2[i].y);
		else if(q2[i].pos>mid&&q2[i].lei==2)
			ans[q2[i].aim]=min(ans[q2[i].aim],-q2[i].x+q2[i].y-maxx1(q2[i].y)),ans[q2[i].aim]=min(ans[q2[i].aim],-q2[i].x-q2[i].y-maxx2(q2[i].y));
	}
	for(int i=l;i<=r;i++)
		if(q2[i].pos<=mid&&q2[i].lei==1)
			clear(q2[i].y),clear2(q2[i].y);
}
int f=0;
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n+m;i++)
		ans[i]=INF;
	for(int i=1;i<=n;i++)
		q1[i].x=getint(),q1[i].y=getint(),q1[i].pos=i,q1[i].lei=1,q1[i].x++,q1[i].y++,shangjie=max(shangjie,q1[i].y),q2[i]=q1[i];
	for(int i=1;i<=m;i++)
		q1[i+n].lei=getint(),q1[i+n].x=getint(),q1[i+n].y=getint(),q1[i+n].x++,q1[i+n].y++,shangjie=max(shangjie,q1[i+n].y),f=q1[i+n].lei==2?f+1:f,q1[i+n].aim=f,q1[i+n].pos=i+n,q2[i+n]=q1[i+n];
//	cout<<f<<endl;
	for(int i=1;i<=shangjie;i++)
		c1[i]=c2[i]=-INF;
	solve1(1,n+m);
	solve2(1,n+m);
	for(int i=1;i<=f;i++)
		printf("%d\n",ans[i]);
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值