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]);
}