zoukankan      html  css  js  c++  java
  • CF319E PingPong

    XV.CF319E Ping-Pong

    好题。

    首先,离线下来离散化显然是不用说的。

    然后观察这里“可以移动”的定义,发现明显可以类比图论中的连边。发现边只有有向边(两区间包含)和无向边(两区间相交)两种,又因为我们只管连通性,所以无向边可以直接使用并查集维护。而包含关系又具有可传递性,故我们最终会发现必定存在一条路径使得最多经过一条有向边(经过多条有向边的路径可以被合并)。于是我们如果使用并查集维护的话,则只需要判断所有互相可达的小区间合并后,询问的两个区间是否相同或者后者包含前者即可。

    然后就是这题的精髓所在了——

    我们将每个区间在线段树中拆成\(\log n\)个区间,使用vector存在节点上。则对于线段树中的某个叶子节点,它的所有父亲节点上的区间中,包含了所有包含当前叶节点的区间。

    于是我们在插入一个区间后,它左右两端所在的节点的所有祖先节点上的区间都与它有交;而因为题目保证插入的区间长度递增,所以这必定连的都是无向边,故我们直接使用并查集合并即可。合并之后,在每个节点的vector内,只需保留当前区间即可。

    在合并完之后,就直接拆区间即可。判断就依靠我们上文提到的性质判断。

    时间复杂度\(O\Big(n\log n\alpha(n)\Big)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,cnt;
    struct oper{
    	int tp,l,r;
    }q[100100];
    vector<int>v[800100],dis;
    int L[100100],R[100100],dsu[100100];
    int find(int x){return dsu[x]==x?x:dsu[x]=find(dsu[x]);}
    #define lson x<<1
    #define rson x<<1|1
    #define mid ((l+r)>>1)
    void merge(int x,int l,int r,int P,int id){
    	if(l>P||r<P)return;
    	if(!v[x].empty()){
    		for(auto ip:v[x])ip=find(ip),dsu[ip]=id,L[id]=min(L[id],L[ip]),R[id]=max(R[id],R[ip]);
    		v[x].clear(),v[x].push_back(id);
    	}
    	if(l!=r)merge(lson,l,mid,P,id),merge(rson,mid+1,r,P,id);
    }
    void assign(int x,int l,int r,int id){
    	if(r<=L[id]||l>=R[id])return;
    	if(L[id]<l&&r<R[id]){v[x].push_back(id);return;}
    	assign(lson,l,mid,id),assign(rson,mid+1,r,id);
    }
    int main(){
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d%d%d",&q[i].tp,&q[i].l,&q[i].r);
    		if(q[i].tp==1)dis.push_back(q[i].l),dis.push_back(q[i].r);
    	}
    	sort(dis.begin(),dis.end()),dis.resize(n=unique(dis.begin(),dis.end())-dis.begin());
    	for(int i=1;i<=m;i++){
    		if(q[i].tp==1){
    			cnt++;
    			dsu[cnt]=cnt,q[i].l=lower_bound(dis.begin(),dis.end(),q[i].l)-dis.begin()+1,q[i].r=lower_bound(dis.begin(),dis.end(),q[i].r)-dis.begin()+1;
    			L[cnt]=q[i].l,R[cnt]=q[i].r;
    			merge(1,1,n,q[i].l,cnt),merge(1,1,n,q[i].r,cnt);
    			assign(1,1,n,cnt);
    		}else{
    			int x=q[i].l,y=q[i].r;
    			x=find(x),y=find(y);
    			puts(x==y||(L[y]<L[x]&&L[x]<R[y])||(L[y]<R[x]&&R[x]<R[y])?"YES":"NO");
    		}
    	}
    	return 0;
    } 
    

  • 相关阅读:
    按钮,文本框
    d01
    第一天,对于课程和工作的了解
    javaweb概念性知识
    Jdbc概念性知识
    连接数据库,和数据增删改
    oracle基础概念性知识
    面向对象java知识汇总题
    javaweb
    date日期
  • 原文地址:https://www.cnblogs.com/Troverld/p/14611268.html
Copyright © 2011-2022 走看看