zoukankan      html  css  js  c++  java
  • CF::Gym 102174G

    我知道我现在应该补eJOI题解,但是如果我真的补了,那我不就不是鸽子了么(大雾

    CF::Gym题目页面传送门

    题意见CF::Gym。

    这显然是个最短路。

    首先假设我们已经很优地把折跃棱镜的效果用边建出来了。设(dis_{i,j})表示第一个县的据点(i)到第二个县的据点(j)的最短路,那么答案显然是(maxlimits_{i=1}^pleft{minlimits_{j=1}^qleft{dis_{x_i,y_j} ight} ight})。这样多源多汇的最短路肯定是吃不消的。考虑一个很简单的优化,建一个虚拟节点,从所有第二个县的建筑据点向这个虚拟节点连长度为(0)的有向边,这样那个式子里面那个(min)就变成(x_i)到虚拟节点的最短路了,就变成一个多源单汇最短路。但还是不能直接求,把边都取反一下,从虚拟节点出发往第一个县的战斗据点走即可跑堆优化Dijkstra。

    接下来考虑怎么“很优地把折跃棱镜的效果用边建出来”。这是一个非常经典的trick:线段树优化建图(没错这可以看作一篇学习笔记)。

    考虑如何从区间([l1,r1])的每个点向区间([l2,r2])的每个点连有向边。只需要建两棵线段树分别表示出和入,每个节点表示它所表示的区间内点的整体(以它为边的端点表示区间内所有点都是端点)(没错,除了叶子都算虚拟节点),这是一个叠加态。我们可以在出树中从每个儿子向爸爸连长度为(0)的有向边、在入树种从每个爸爸向儿子连长度为(0)的有向边来实现叠加态具体化。然后新建虚拟节点,将([l1,r1])在出树中分解成若干个节点,都连向虚拟节点,再从虚拟节点连向([l2,r2])在入树中分解成的若干节点。至于边权,你只需要使所有出边边权相同、所有入边边权相同,并且出边边权加入边边权等于原问题中的边权,正确性都显然(一般会令出边边权为原问题边权,入边边权为(0))。这样边数复杂度显然是(mathrm O(log n))的。

    回到本题。遗憾的是,线段树优化建图并没法一次性建无向边,因为要无向的话,首先两棵线段树内爸爸儿子连接的边都得无向,这么一来整棵树都连通了,就乱了套了。于是可以把一条无向边拆成两条有向边。

    最终边数复杂度(mathrm O(mlog n)),加上Dijkstra的(log),时间复杂度为(mathrm O!left(mlog^2n ight))(由于线段树点数是线性的,所以总点数依然是(mathrm O(n)),只不过一个线段树常数是(4),总常数至少有(16)/fad)。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define pb push_back
    #define mp make_pair
    #define X first
    #define Y second
    const int inf=0x3f3f3f3f3f3f3f3f;
    const int N=100000,M=100000; 
    int n,m,s,t;
    int a[N+1],b[N+1];
    int now;//目前节点数量 
    vector<pair<int,int> > nei[18*N+2*M+2];//邻接表 
    struct segtree{//优化建图的线段树(4个线段树放一起) 
    	struct node{int l,r,nd[4]/*4个线段树分别保存的节点*/;}nd[N<<2];
    	#define l(p) nd[p].l
    	#define r(p) nd[p].r
    	#define nd(p) nd[p].nd
    	void bld(int l=1,int r=n,int p=1){//建树 
    		l(p)=l;r(p)=r;
    		if(l==r)return nd(p)[0]=nd(p)[3]=l,nd(p)[1]=nd(p)[2]=l+n,void();//叶子的节点是实点 
    		nd(p)[0]=++now;nd(p)[1]=++now;nd(p)[2]=++now;nd(p)[3]=++now;//非叶子的节点是虚点 
    		int mid=l+r>>1;
    		bld(l,mid,p<<1);bld(mid+1,r,p<<1|1);
    		nei[nd(p<<1)[0]].pb(mp(nd(p)[0],0));nei[nd(p<<1|1)[0]].pb(mp(nd(p)[0],0));//出,儿子向爸爸连边 
    		nei[nd(p)[1]].pb(mp(nd(p<<1)[1],0));nei[nd(p)[1]].pb(mp(nd(p<<1|1)[1],0));//入,爸爸向儿子连边 
    		nei[nd(p<<1)[2]].pb(mp(nd(p)[2],0));nei[nd(p<<1|1)[2]].pb(mp(nd(p)[2],0));//出,儿子向爸爸连边 
    		nei[nd(p)[3]].pb(mp(nd(p<<1)[3],0));nei[nd(p)[3]].pb(mp(nd(p<<1|1)[3],0));//入,爸爸向儿子连边 
    	}
    	void init(){bld();}
    	void ae(int l,int r,int id,int v,int len,bool out,int p=1){
    		if(l<=l(p)&&r>=r(p))return out?nei[nd(p)[id]].pb(mp(v,len)):nei[v].pb(mp(nd(p)[id],len)),void();//与虚拟节点相连 
    		int mid=l(p)+r(p)>>1;
    		if(l<=mid)ae(l,r,id,v,len,out,p<<1);
    		if(r>mid)ae(l,r,id,v,len,out,p<<1|1);
    	}
    }segt;
    bool vis[18*N+2*M+2];
    int dis[18*N+2*M+2];
    void dijkstra(){//堆优化Dijkstra 
    	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
    	memset(dis,0x3f,sizeof(dis));
    	q.push(mp(dis[now]=0,now));
    	while(q.size()){
    		int x=q.top().Y;
    		q.pop();
    		if(vis[x])continue;
    		vis[x]=true;
    		for(int i=0;i<nei[x].size();i++){
    			int y=nei[x][i].X,len=nei[x][i].Y;
    			if(dis[x]+len<dis[y])q.push(mp(dis[y]=dis[x]+len,y));
    		}
    	}
    }
    signed main(){
    	cin>>n>>m>>s>>t;
    	now=2*n;
    	segt.init();//线段树初始化 
    	while(m--){
    		int l1,r1,l2,r2,len;
    		scanf("%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&len);
    		segt.ae(l1,r1,0,++now,len,true);segt.ae(l2,r2,1,now,0,false);//一个方向 
    		segt.ae(l2,r2,2,++now,len,true);segt.ae(l1,r1,3,now,0,false);//另一个方向 
    	}
    	for(int i=1;i<=s;i++)scanf("%lld",a+i);
    	for(int i=1;i<=t;i++)scanf("%lld",b+i);
    	now++;//单源 
    	for(int i=1;i<=t;i++)nei[now].pb(mp(b[i]+n,0)); 
    	dijkstra();
    	int ans=0;
    	for(int i=1;i<=s;i++)ans=max(ans,dis[a[i]]);//答案 
    	if(ans>=inf)puts("boring game");
    	else cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    数据分析系统DIY1/3:CentOS7+MariaDB安装纪实
    NSArray与NSString、NSData,NSDictionary与NSString、NSData 相互转化
    Geek地生活,文艺地思考
    Android开发中遇到的问题(五)——Eclipse导入Android项目出现"Invalid project description overlaps the location of another project"错误的解决办法
    Android开发中遇到的问题(四)——Android中WARNING: Application does not specify an API level requirement!的解决方法
    Android开发中遇到的问题(三)——eclipse创建android项目无法正常预览布局文件
    Android开发中遇到的问题(二)——新建android工程的时候eclipse没有生成MainActivity和layout布局
    Android开发学习总结(三)——appcompat_v7项目说明
    Android开发学习总结(二)——使用Android Studio搭建Android集成开发环境
    Android开发学习总结(一)——搭建最新版本的Android开发环境
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/CF-Gym-102174G.html
Copyright © 2011-2022 走看看