zoukankan      html  css  js  c++  java
  • 2019.01.02-dtoj-4100-yjqb

    题目描述:

    给定一个二分图,两个部分我们称之为A部和B部。
    对于一个A部的点A,其在B部中相邻的点是一个连续的区间,记为[Li,Ri]。
    现在你需要找一个尽量大的匹配,使之在具有匹配的性质的前提下,所有匹配边互不相交。(即不存在两条匹配边(Ai,Bx),(Aj,By),使得(i<j,x>y))。

    算法标签:dp,splay

    思路:

    令f[i][j],i表示A部匹配到第i个,j表示B部匹配到第j个

    有以下两个转移式:

    f[i][j]=f[i-1][j];
    对于li≤j≤ri,f[i][j]=f[i-1][j-1]+1;

    我们发现两个式子都只与i-1有关,于是我们可以把第二维消去。观察发现,每一位与前一位的差值只为0或1。于是考虑差分,并且用splay维护区间关系。

    每次把ri后的第一个1删去,没有1则删去最后一个0,在li的位置上加上一个1,表示把整个[Li,Ri]区间右移一格,并且选中区间的第一个比前一个多1。

    统计答案看总共有多少个1即可。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e5+5;
    int n,l[N],r[N],rt,sum[N],son[N][2],sz[N],val[N],fa[N];
    il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
    il void update(int x){
        sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;
        sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x];
    }
    il void build(int x,int l,int r){
        int mid=(l+r)>>1;fa[mid]=x;
        if(mid<x)son[x][0]=mid;else son[x][1]=mid;
        if(l<mid)build(mid,l,mid-1);
        if(mid<r)build(mid,mid+1,r);
        sz[mid]=sz[son[mid][0]]+sz[son[mid][1]]+1;
    }
    il void rotate(int x,int &k){
        int y=fa[x],z=fa[y],tp=(son[y][1]==x);
        if(y!=k)son[z][son[z][1]==y]=x;else k=x;
        son[y][tp]=son[x][tp^1];fa[son[y][tp]]=y;
        son[x][tp^1]=y;fa[y]=x;fa[x]=z;
        sz[x]=sz[y];sum[x]=sum[y];
        update(y);
    }
    il void splay(int x,int &k){
        while(x!=k){
            int y=fa[x],z=fa[y];
            if(y!=k)((son[y][0]==x)^(son[z][0]==y))?rotate(x,k):rotate(y,k);
            rotate(x,k);
        }
    }
    il int kth(int x,int k){
        if(sz[son[x][0]]+1==k)return x;
        if(sz[son[x][0]]>=k)return kth(son[x][0],k);
        return kth(son[x][1],k-1-sz[son[x][0]]);
    }
    il int fp(int x){
        if(sum[son[x][0]])return fp(son[x][0]);
        if(val[x])return x;
        return fp(son[x][1]);
    }
    il void del(int x){   
        splay(x,rt);
        int rk=sz[son[x][0]]+1;
        int a=kth(rt,rk-1),b=kth(rt,rk+1);
        splay(a,rt);splay(b,son[a][1]);
        if(val[x])sum[a]--,sum[b]--,val[x]=0;
        son[b][0]=sz[x]=fa[x]=0;sz[a]--;sz[b]--;
    }
    int main()
    {
      n=read();for(int i=1;i<=n;i++)l[i]=read(),r[i]=read();
      build(0,1,n+2);rt=(n+3)>>1;
        for(int i=1;i<=n;i++){
            int x=kth(rt,r[i]);
            splay(x,rt);
            if(sum[son[x][1]])x=fp(son[x][1]);
            else while(son[x][1])x=son[x][1];
            del(x);
            int a=kth(rt,l[i]),b=kth(rt,l[i]+1);
            splay(a,rt);splay(b,son[a][1]);
            son[b][0]=x;val[x]=sum[x]=sz[x]=1;
            sum[a]++;sum[b]++;sz[a]++;sz[b]++;fa[x]=b;
        }
        printf("%d
    ",sum[rt]);
        return 0;
    }
    View Code
  • 相关阅读:
    UEFI启动 安装win8 win10 及windows server 2012 最简单的方法
    Android SDK中国在线更新镜像服务器 解决GOOGLE更新无法下载 更新失败的问题
    DELPHI 单元文件结构
    获取程序自身大小的2个函数
    实时获取网络时间 并转换为北京时间的函数
    部署maven的一些要点、遇到的问题
    cron表达式详解
    redhat安装xwindow环境
    tomcat执行文件权限
    一个方便的java分页算法
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10211995.html
Copyright © 2011-2022 走看看