1 条题解

  • 0
    @ 2022-4-16 9:09:08

    Update

    • 20210811 格式已修。

    前言

    听说这是道线段树优化 dp 板子题?比赛时一堆人没搞出来?

    那我们就来分析一下这题怎么搞罢。


    题意

    给你 n×mn\times m 矩形上一些横向的全 11 线段,然后让你删去最少的行,使得任意相邻两行都存在 11 在同一列。

    要求输出方案。

    线段可能重叠。


    思路

    看到不在同一行的线段及可能重叠,想到上扫描线

    从左往右扫描,把当前扫描线上的点放进一个数据结构中。

    对每个新插入的点,找到其前驱、后继,与之相连

    然后便可以直接从前往后进行 dp 找出留下来的最多点及点集(即 dp 时记录路径)了,剩下的点即答案。

    正确性显然,大概就是每次插点时原本其前驱、后继相连,现在在中间新加一个点后必然更优,其它情况可以继续与它间接相连,于是正确性得证。(默认第 00 行与第 n+1n+1 行全是 11

    什么,你问我这个支持动态加点、删点、找前驱后继的数据结构是什么?

    平衡树啊。

    其实可以直接用 set,但反正我直接上 Splay 了。

    当然,如果你写线段树,也是可以的。


    Code

    调试信息没有删,但意义还是清楚的。

    前面的 Splay 码头可以仅大致浏览一下。

    #include <algorithm>
    #include <stdio.h>
    #include <vector>
    typedef long long llt;
    typedef unsigned uint;typedef unsigned long long ullt;
    typedef bool bol;typedef char chr;typedef void voi;
    typedef double dbl;
    template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
    template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
    template<typename T>T power(T base,T index,T mod){return((index<=1)?(index?base:1):(power(base*base%mod,index>>1,mod)*power(base,index&1,mod)))%mod;}
    template<typename T>T lowbit(T n){return n&-n;}
    template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
    template<typename T>T lcm(T a,T b){return(a!=0||b!=0)?a/gcd(a,b)*b:(T)0;}
    template<typename T,typename len_def>
    class Splay
    {
        public:
            Splay():rot(NULL){}
            ~Splay(){if(rot!=NULL)delete rot;}
            len_def size(){return(rot==NULL)?0:rot->siz;}
            voi bzr(){if(rot!=NULL)delete rot;rot=NULL;}
            voi insert(T key,len_def cnt=1)
            {
                if(rot==NULL){rot=new node(cnt),rot->key=key;return;}
                node*p=rot,*f=NULL;
                do
                {
                    if(p->key==key){p->cnt+=cnt,p->resize();if(f!=NULL)f->resize();splay(p);return;}
                    if((f=p,p=p->son[p->key<key])==NULL)
                    {
                        p=new node(cnt),p->key=key,p->fath=f,f->son[f->key<key]=p,f->resize(),splay(p);
                        return;
                    }
                }
                while(true);
            }
            voi cut(T key,len_def cnt=1)
            {
                node*p=rot,*f=NULL;
                while(p!=NULL)
                {
                    if(p->key==key)
                    {
                        p->cnt=(cnt<p->cnt)?p->cnt-cnt:0,p->resize();
                        if(f!=NULL)f->resize();
                        splay(p);return;
                    }
                    f=p,p=p->son[p->key<key];
                }
                splay(f);
            }
            voi make_count(T key,len_def cnt)
            {
                if(cnt==0){erase_all(key);return;}
                if(rot==NULL){rot=new node(cnt),rot->key=key;return;}
                node*p=rot,*f=NULL;
                do
                {
                    if(p->key==key){p->cnt=cnt,p->resize();if(f!=NULL)f->resize();splay(p);return;}
                    if((f=p,p=p->son[p->key<key])==NULL)
                    {
                        p=new node(cnt),p->key=key,p->fath=f,f->son[f->key<key]=p,f->resize(),splay(p);
                        return;
                    }
                }
                while(true);
            }
            voi erase(T key,len_def cnt=1)
            {
                if(rot==NULL)return;
                rank(key);node*p=rot;
                if(p->key!=key)return;
                if(cnt<p->cnt){p->cnt-=cnt,p->siz-=cnt;return;}
                if(p->son[0]==NULL&&p->son[1]==NULL){bzr();return;}
                if(p->son[0]==NULL){rot=p->son[1],rot->fath=NULL,kill(p);return;}
                if(p->son[1]==NULL){rot=p->son[0],rot->fath=NULL,kill(p);return;}
                pre(),p->son[1]->fath=rot,rot->son[1]=p->son[1],kill(p),rot->resize();
            }
            voi erase_all(T key)
            {
                if(rot==NULL)return;
                rank(key);node*p=rot;
                if(p->key!=key)return;
                if(p->son[0]==NULL&&p->son[1]==NULL){bzr();return;}
                if(p->son[0]==NULL){rot=p->son[1],rot->fath=NULL,kill(p);return;}
                if(p->son[1]==NULL){rot=p->son[0],rot->fath=NULL,kill(p);return;}
                pre(),p->son[1]->fath=rot,rot->son[1]=p->son[1],kill(p),rot->resize();
            }
            len_def count(T key)
            {
                node*p=rot,*last=NULL;
                do
                {
                    if(p==NULL)return splay(last),0;
                    if(key==p->key)break;
                    p=p->son[p->key<key];
                }
                while(true);
                return splay(p),p->cnt;
            }
            len_def rank(T key)
            {
                len_def ans=0;node*p=rot,*last=NULL;
                while(p!=NULL)
                    if(key<p->key)last=p,p=p->son[0];
                    else
                    {
                        if(p->son[0]!=NULL)ans+=p->son[0]->siz;
                        if(key==p->key)return splay(p),ans;
                        ans+=p->cnt,last=p,p=p->son[1];
                    }
                return splay(last),ans;
            }
            T kth(len_def k)
            {
                node*p=rot;
                while(p!=NULL)
                    if(p->son[0]!=NULL&&k<p->son[0]->siz)p=p->son[0];
                    else
                    {
                        if(p->son[0]!=NULL)k-=p->son[0]->siz;
                        if(k<p->cnt)break;
                        k-=p->cnt,p=p->son[1];
                    }
                return splay(p),p->key;
            }
            T pre(T key){insert(key),pre();T ans=rot->key;erase(key);return ans;}
            T nxt(T key){insert(key),nxt();T ans=rot->key;erase(key);return ans;}
        private:
            class node
            {
                public:
                    T key;len_def cnt,siz;node*son[2],*fath;
                    node(len_def cnt=1){siz=this->cnt=cnt,son[0]=son[1]=fath=NULL;}
                    ~node(){if(son[0]!=NULL)delete son[0];if(son[1]!=NULL)delete son[1];}
                    voi resize()
                    {
                        siz=cnt;
                        if(son[0]!=NULL)siz+=son[0]->siz;
                        if(son[1]!=NULL)siz+=son[1]->siz;
                    }
                    bol howson(){return this==fath->son[1];}
                    voi rotate()
                    {
                        node*f=fath;
                        if(f==NULL)return;
                        node*ff=f->fath;
                        bol sk=howson();
                        if(ff!=NULL)ff->son[f->howson()]=this;
                        f->son[sk]=son[!sk];
                        if(son[!sk]!=NULL)son[!sk]->fath=f;
                        son[!sk]=f,f->fath=this,fath=ff,f->resize(),resize();
                    }
            };
            node*rot;
            voi splay(node*p)
            {
                if(p==NULL)return;
                while(p->fath!=NULL)
                {
                    if(p->fath->fath!=NULL)((p->howson()==p->fath->howson())?p->fath:p)->rotate();
                    p->rotate();
                }
                rot=p;
            }
            voi kill(node*p){p->son[0]=p->son[1]=NULL;delete p;}
            node*pre()
            {
                node*p=rot->son[0];
                if(p==NULL)return NULL;
                while(p->son[1]!=NULL)p=p->son[1];
                return splay(p),p;
            }
            node*nxt()
            {
                node*p=rot->son[1];
                if(p==NULL)return NULL;
                while(p->son[0]!=NULL)p=p->son[0];
                return splay(p),p;
            }
    };
    typedef std::pair<ullt,uint>Pair;
    int In[300005];
    Pair P[1919810];
    std::vector<uint>Way[300005];
    Splay<int,uint>S;
    uint DP[300005],Last[300005];
    int main()
    {
    	uint n,m,u,l,r;scanf("%u%u",&n,&m);
    	for(uint i=0;i<m;i++)scanf("%u%u%u",&u,&l,&r),P[i<<1]=Pair((ullt)l*2-1,--u),P[(i<<1)|1]=Pair((ullt)r*2,u);
    	std::sort(P,P+(m<<=1));
    	S.insert(-1),S.insert(n);
    	for(uint i=0;i<m;i++)
    	{
    		u=P[i].second;
    		if(P[i].first&1)
    		{
    			int p=S.pre(u),q=S.nxt(u);
    			if(~p)Way[u].push_back(p);
    			if((uint)q<n)Way[q].push_back(u);
    			S.insert(u);
    			In[u]++;
    		}
    		else S.erase(u),In[u]--;
    	}
    	uint ans=0;
    	u=-1;
    	for(uint i=0;i<n;i++)
    	{
    		Last[i]=-1;
    		// printf("%u:",i+1);
    		for(auto p:Way[i])
    		{
    			if(_max(DP[i],DP[p]))Last[i]=p;
    			// printf("%u ",p+1);
    		}
    		// putchar('\n');
    		if(_max(ans,++DP[i]))u=i;
    	}
    	while(~u)In[u]=true,u=Last[u];
    	ans=n-ans;
    	printf("%u\n",ans);
    	for(uint i=0;i<n;i++)if(!In[i])
    		printf("%u%c",i+1,(--ans)?' ':'\n');
    	return 0;
    }
    
    • 1

    信息

    ID
    7221
    时间
    2000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    2
    已通过
    2
    上传者