分治学习笔记

这是一个古老的坑了。孩子真不会分治怎么办(雾

去LOJ上扒了几道题做 主要就是纯分治和CDQ分治 反而点分治 陈老师二分还有分治FFT都还会亚子(我丢 我好难

 

JOISC2014 Day 3 稻草人

分治以后考虑维护上方的递增单调栈,下方的递减单调栈,然后二分位置确定每一个答案就好了。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 200010
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct poi{int x,y;}p[N];
bool cmpx(poi a,poi b){return a.x<b.x;}
bool cmpy(poi a,poi b){return a.y<b.y;}
int stk1[N],stk2[N],n1,n2; ll fin;
void solve(int l,int r)
{
    if(l==r)    return;
    int mid=l+r>>1;
    solve(l,mid); solve(mid+1,r);
    sort(p+l,p+mid+1,cmpx); sort(p+mid+1,p+r+1,cmpx);
    int j=l; n1=n2=0;
    for(int i=mid+1;i<=r;i++)
    {
        while(n2 && p[i].y<p[stk2[n2]].y)    n2--;
        stk2[++n2]=i;
        while(j<=mid && p[j].x<p[i].x)
        {
            while(n1 && p[j].y>p[stk1[n1]].y)    n1--;
            stk1[++n1]=j; j++;
        }
        int lpos=1,rpos=n1,ans=0;
        while(lpos<=rpos)
        {
            int mid=lpos+rpos>>1;
            if(p[stk1[mid]].x>p[stk2[n2-1]].x)
                ans=mid,rpos=mid-1;
            else    lpos=mid+1;
        }
        if(ans)    fin+=n1-ans+1;
    }
}
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
        p[i].x=read(),p[i].y=read();
    p[0].x=p[0].y=-1; sort(p+1,p+n+1,cmpy);
    solve(1,n); printf("%lld\n",fin);
    return 0;
}
View Code

 

「TJOI / HEOI2016」序列

朴素DP长这样

$f[i] = max(f[i],f[j]+1)$

$i>j$ $a[i]>=mx[j]$ $mn[i]>=a[j]$

一眼三维偏序上CDQ就好啦

好像裸上树套树的人更多(毒瘤!

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 100010
#define lowbit(x) (x&-x)
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct node{int a,mx,mn,f,id;}a[N];
struct bit
{
    int t[N],n;
    void mfy(int x,int v){while(x<=n) t[x]=max(t[x],v),x+=lowbit(x);}
    int qry(int x){int ans=0; while(x) ans=max(ans,t[x]),x-=lowbit(x); return ans;}
    void del(int x){while(x<=n)    t[x]=0,x+=lowbit(x);}
}b;
bool cmpi(node x,node y){return x.id<y.id;}
bool cmpa(node x,node y){return x.a<y.a;}
bool cmpn(node x,node y){return x.mn<y.mn;}
void solve(int l,int r)
{
    if(l==r)    return; int mid=l+r>>1;
    solve(l,mid);
    sort(a+l,a+mid+1,cmpa); sort(a+mid+1,a+r+1,cmpn);
    int w=l;
    for(int i=mid+1;i<=r;i++)
    {
        while(w<=mid && a[w].a<=a[i].mn)
            b.mfy(a[w].mx,a[w].f),w++;
        a[i].f=max(a[i].f,b.qry(a[i].a)+1);
    }
    for(int i=l;i<w;i++)    b.del(a[i].mx);
    sort(a+mid+1,a+r+1,cmpi);
    solve(mid+1,r);
}
int main()
{
    int n=read(),m=read(); b.n=n;
    for(int i=1;i<=n;i++)    a[i].mn=a[i].mx=a[i].a=read(),a[i].id=i,a[i].f=1;
    for(int i=1;i<=m;i++)
    {
        int x=read(),v=read();
        a[x].mx=max(a[x].mx,v);
        a[x].mn=min(a[x].mn,v);
    }
    solve(1,n); int ans=0;
    for(int i=1;i<=n;i++)    ans=max(ans,a[i].f);
    printf("%d\n",ans);
    return 0;
}
View Code

 

【BZOJ2989】数列

看起来有两个绝对值能想到什么呢!曼哈顿距离!

简单的转欧式距离就是二维数点啦!

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define N 600010
#define nd 250010
#define lowbit(x) (x&-x)
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct bit
{
    int t[N],n;
    void modify(int x,int v){while(x<=n)    t[x]+=v,x+=lowbit(x);}
    int query(int x){int ans=0; while(x) ans+=t[x],x-=lowbit(x); return ans;}
    int ask(int x,int y){return query(y)-query(x-1);}
}b;
struct node{int type,x,y,k,id;}a[N],tmp[N];
bool cmpx(node x,node y){return x.x==y.x?x.type>y.type:x.x<y.x;}
int f[N];
void solve(int l,int r)
{
    if(l==r)    return;
    int mid=l+r>>1,t=0; solve(l,mid);
    for(int i=l;i<=mid;i++)    if(!a[i].type)
        tmp[++t]=a[i];
    for(int i=mid+1;i<=r;i++)    if(a[i].type)
    {
        tmp[++t]=(node){+1,a[i].x-a[i].k,a[i].y,a[i].k,a[i].id};
        tmp[++t]=(node){-1,a[i].x+a[i].k,a[i].y,a[i].k,a[i].id};
    }
    sort(tmp+1,tmp+t+1,cmpx);
    for(int i=1;i<=t;i++)
        if(!tmp[i].type)    b.modify(tmp[i].y,1);
        else    f[tmp[i].id]-=tmp[i].type*b.ask(tmp[i].y-tmp[i].k,tmp[i].y+tmp[i].k);
    for(int i=1;i<=t;i++)    if(!tmp[i].type)
        b.modify(tmp[i].y,-1);
    solve(mid+1,r);
}
int top,v[N],fq; char ch[20];
int main()
{
    int n=read(),q=read(),x,y;
    for(int i=1;i<=n;i++)
        v[i]=read(),a[++top]=(node){0,i+v[i],i-v[i]+nd,0,0};
    for(int i=1;i<=q;i++)
    {
        scanf("%s",ch); x=read(),y=read();
        if(ch[0]=='Q')
            a[++top]=(node){1,x+v[x],x-v[x]+nd,y,++fq};
        else
            v[x]=y,a[++top]=(node){0,x+v[x],x-v[x]+nd,0,0};
    }
    b.n=nd+nd; solve(1,top);
    for(int i=1;i<=fq;i++)
        printf("%d\n",f[i]);
    return 0;
}
View Code

 

平面最近点对

——孩子发现自己这个都不会,还有救吗?

——应该扔了。(逃

貌似就是分治下去,然后暴力,至于复杂度为什么是对的,好像有证明说这样的点不超过6个?

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 1e18
#define db double
#define eps 1e-8
#define N 200010
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct poi
{
    db x,y;
    poi(){}
    poi(db _x,db _y){x=_x,y=_y;}
}p[N],L[N],R[N];
bool operator<(poi a,poi b){return a.x<b.x;}
db dis(poi x,poi y){return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));}
void print(poi a){printf("%lf %lf\n",a.x,a.y);}
db solve(int l,int r)
{
    if(l==r)    return inf; int mid=l+r>>1;
    db d1=solve(l,mid),d2=solve(mid+1,r);
    db d=min(d1,d2); int nl=0,nr=0;
    for(int i=mid;i>=l;i--)    if(p[mid].x-p[i].x<=d)
        L[++nl]=p[i]; else    break;
    for(int i=mid+1;i<=r;i++)    if(p[i].x-p[mid].x<=d)
        R[++nr]=p[i]; else    break;
    for(int i=1;i<=nl;i++)    for(int j=1;j<=nr;j++)
        d=min(d,dis(L[i],R[j]));
    return d;
}
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    sort(p+1,p+n+1);
    printf("%.4lf",solve(1,n));
    return 0;
}
View Code

 

BJWC2011 最小三角形

经过上个题的经验,于是这个题我直接重新加工了一下,在改变循环顺序,强行剪枝以后依然只能拿到90分的好成绩。

膜了一发题解,发现好像区别也并不大?把y再排一遍序好像可以降很多复杂度。至于为什么是对的,我也没找到证明。咱也不知道,咱也不敢问。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 1e18
#define db double
#define eps 1e-8
#define N 200010
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct poi
{
    db x,y;
    poi(){}
    poi(db _x,db _y){x=_x,y=_y;}
}p[N],L[N],R[N];
bool operator<(poi a,poi b){return a.x<b.x;}
db dis(poi x,poi y){return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));}
void print(poi a){printf("%lf %lf\n",a.x,a.y);}
db solve(int l,int r)
{
    if(l==r)    return inf; int mid=l+r>>1;
    db d1=solve(l,mid),d2=solve(mid+1,r);
    db d=min(d1,d2); int nl=0,nr=0;
    for(int i=mid;i>=l;i--)    if(p[mid].x-p[i].x<=d/2)
        L[++nl]=p[i]; else    break;
    for(int i=mid+1;i<=r;i++)    if(p[i].x-p[mid].x<=d/2)
        R[++nr]=p[i]; else    break;
    for(int i=1;i<=nl;i++)    for(int j=i+1;j<=nl;j++)
        if(dis(L[i],L[j])*2<=d)    for(int k=1;k<=nr;k++)
            d=min(d,dis(L[i],R[k])+dis(L[i],L[j])+dis(L[j],R[k]));
    for(int j=1;j<=nr;j++)    for(int k=j+1;k<=nr;k++)
        if(dis(R[j],R[k])*2<=d)    for(int i=1;i<=nl;i++)
            d=min(d,dis(L[i],R[k])+dis(L[i],R[j])+dis(R[j],R[k]));
    return d;
}
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    sort(p+1,p+n+1);
    printf("%.6lf",solve(1,n));
    return 0;
}
90pts
//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 1e18
#define db double
#define eps 1e-8
#define N 200010
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct poi
{
    db x,y;
    poi(){}
    poi(db _x,db _y){x=_x,y=_y;}
}p[N],w[N];
bool operator<(poi a,poi b){return a.x<b.x;}
bool cmpy(poi a,poi b){return a.y<b.y;}
db dis(poi x,poi y){return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));}
void print(poi a){printf("%lf %lf\n",a.x,a.y);}
db solve(int l,int r)
{
    if(l==r)    return inf; int mid=l+r>>1;
    db d1=solve(l,mid),d2=solve(mid+1,r);
    db d=min(d1,d2),lim=d/2; int nw=0;
    for(int i=mid;i>=l;i--)    if((p[mid].x-p[i].x)<=lim)
        w[++nw]=p[i]; else    break;
    for(int i=mid+1;i<=r;i++)    if((p[i].x-p[mid].x)<=lim)
        w[++nw]=p[i]; else    break;
    sort(w+1,w+nw+1,cmpy);
    for(int i=1,j=1;i<=nw;i++)
    {
        while(j<=nw && (w[j].y-w[i].y)<=lim)
            j++;
        for(int k=i+1;k<j;k++)    for(int l=k+1;l<j;l++)
            d=min(d,dis(w[i],w[k])+dis(w[i],w[l])+dis(w[l],w[k]));
    }
    return d;
}
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    sort(p+1,p+n+1);
    printf("%.6lf",solve(1,n));
    return 0;
}
100pts

 

posted @ 2019-09-24 16:25  寒雨微凝  阅读(277)  评论(0编辑  收藏  举报