BZOJ4071: [APIO2015]八邻旁之桥

BZOJ4071: [APIO2015]八邻旁之桥

这个题也变成了权限题,不是很懂为什么。。。

反正没钱氪金。。。

这里附上洛谷的题面:

洛谷P3644 [APIO2015]八邻旁之桥

题目描述

一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 AA 和区域 BB。

每一块区域沿着河岸都建了恰好$1000000001$栋的建筑,每条岸边的建筑都从$ 0$ 编号到 $1000000000$。相邻的每对建筑相隔 $1$ 个单位距离,河的宽度也是 $1$ 个单位长度。

区域 $A$ 中的$ i$ 号建筑物恰好与区域 $B$ 中的 $i$ 号建筑物隔河相对。

城市中有$ N$ 个居民。第 $i$ 个居民的房子在区域$ P_i$ 的$ S_i$号建筑上,同时他的办公室坐落在$ Q_i$ 区域的$ T_i$ 号建筑上。

一个居民的房子和办公室可能分布在河的两岸,这样他就必须要搭乘船只才能从家中去往办公室,这种情况让很多人都觉得不方便。为了使居民们可以开车去工作,政府决定建造不超过 KK 座横跨河流的大桥。

由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。

当政府建造最多$ K$ 座桥之后,设 $D_i$ 表示第$ i$ 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得$ D_1 + D_2 + \cdots + D_N$ 最小。

输入输出格式

输入格式:

 

输入的第一行包含两个正整数$ K$ 和 $N$,分别表示桥的上限数量和居民的数量。

接下来 NN 行,每一行包含四个参数:$P_i, S_i, Q_i$ 和$ T_i$,表示第$ i$ 个居民的房子在区域 $P_i$的$ S_i$ 号建筑上,且他的办公室位于 $Q_i$ 区域的 $T_i$ 号建筑上。

 

输出格式:

 

输出仅为一行,包含一个整数,表示$ D_1 + D_2 + \cdots + D_N$ 的最小值。

 

输入输出样例

输入样例#1: 复制
1 5
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
输出样例#1: 复制
24
输入样例#2: 复制
2 5
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
输出样例#2: 复制
22

说明

【数据范围】

所有数据都保证:$P_i$ 和 $Q_i$ 为字符 “A” 和 “B” 中的一个, $0 \leq S_i, T_i \leq 1000000000$,同一栋建筑内可能有超过$ 1$ 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 $1$)。

子任务 1 (8 分)$K = 1$

$1 \leq N \leq 1000$

子任务 2 (14 分)$K = 1$

$1 \leq N \leq 100000$

子任务 3 (9 分)$K = 2$

$1 \leq N \leq 100$

子任务 4 (32 分)$K = 2$

$1 \leq N \leq 1000$

子任务 5 (37 分)$K = 2$

$1 \leq N \leq 100000$


题解Here!

又是一道把两个相似的题强行拼接在一起的题。。。
直接分类讨论:
当$k==1$的时候:
如果工作地点在一侧,那么路程就是$r-l$。
然后我们对于不在一侧的线段端点求个中位数,这样肯定能使总路程最小。
不过,$k==1$的情况没有必要线段树,直接丢进数组里排个序,就可以求出中位数了。
当$k==2$的时候:
取每个线段的中点,如果靠近左边的桥,就往左边过桥,否则往右边过桥。
枚举一个分割点,然后两边都是$k==1$的情况,用线段树求$\sum|\text{位置}-\text{中位数}|$。
附代码:(我分了两个$namespace$来写)

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 1000010
using namespace std;
int n,k;
int top=0,stack[MAXN];
long long ans=0;
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline long long abs(const long long x){return x>0?x:-x;}
namespace one{
	int m=0;
	void main(){
		char ch[2];
		int x,y,p,q;
		for(int i=1;i<=n;i++){
			scanf("%s",ch);x=read();p=ch[0]-'A';
			scanf("%s",ch);y=read();q=ch[0]-'A';
			if(p==q){
				ans+=abs(x-y);
				continue;
			}
			else if(p==1)swap(x,y);
			m++;
			stack[++top]=x;stack[++top]=y;
		}
		sort(stack+1,stack+top+1);
		int mid=stack[top>>1];
		for(int i=1;i<=top;i++)ans+=abs(mid-stack[i]);
		printf("%lld\n",ans+m);
	}
}
namespace two{
	#define LSON rt<<1
	#define RSON rt<<1|1
	#define DATA(rt) a[rt].data
	#define SUM(rt) a[rt].sum
	#define LSIDE(rt) a[rt].l
	#define RSIDE(rt) a[rt].r
	int num=0;
	long long s[MAXN];
	struct Line{
		int x,y;
		friend bool operator <(const Line &p,const Line &q){
			return (p.x+p.y)<(q.x+q.y);
		}
	}line[MAXN];
	struct Segment_Tree{
		long long data,sum;
		int l,r;
	}a[MAXN<<2];
	inline void add_line(int x,int y){
		num++;
		line[num].x=x;line[num].y=y;
	}
	inline void pushup(int rt){
		DATA(rt)=DATA(LSON)+DATA(RSON);
		SUM(rt)=SUM(LSON)+SUM(RSON);
	}
	void buildtree(int l,int r,int rt){
		LSIDE(rt)=l;RSIDE(rt)=r;DATA(rt)=SUM(rt)=0;
		if(l==r)return;
		int mid=l+r>>1;
		buildtree(l,mid,LSON);
		buildtree(mid+1,r,RSON);
	}
	void update(int k,int v,int rt){
		DATA(rt)++;SUM(rt)+=v;
		if(LSIDE(rt)==RSIDE(rt))return;
		int mid=LSIDE(rt)+RSIDE(rt)>>1;
		if(k<=mid)update(k,v,LSON);
		else update(k,v,RSON);
	}
	long long query(int k,int rt){
		if(LSIDE(rt)==RSIDE(rt))return 1LL*stack[LSIDE(rt)]*k;
		if(k<=DATA(LSON))return query(k,LSON);
		else return SUM(LSON)+query(k-DATA(LSON),RSON);
	}
	inline long long ask(int x){return SUM(1)-2LL*query(x,1);}
	void work(){
		buildtree(1,top,1);
		for(int i=1;i<=num;i++){
			line[i].x=lower_bound(stack+1,stack+top+1,line[i].x)-stack;
			line[i].y=lower_bound(stack+1,stack+top+1,line[i].y)-stack;
			update(line[i].x,stack[line[i].x],1);
			update(line[i].y,stack[line[i].y],1);
			s[i]=ask(i);
		}
		long long minn=s[num];
		buildtree(1,top,1);
		for(int i=num;i>=1;i--){
			update(line[i].x,stack[line[i].x],1);
			update(line[i].y,stack[line[i].y],1);
			minn=min(minn,s[i-1]+ask(num-i+1));
		}
		printf("%lld\n",minn+ans);
	}
	void main(){
		char ch[2];
		int x,y,p,q;
		for(int i=1;i<=n;i++){
			scanf("%s",ch);x=read();p=ch[0]-'A';
			scanf("%s",ch);y=read();q=ch[0]-'A';
			if(p==q){
				ans+=abs(x-y);
				continue;
			}
			ans++;
			stack[++top]=x;stack[++top]=y;
			if(x>y)swap(x,y);
			add_line(x,y);
		}
		if(!num){
			printf("%lld\n",ans);
			return;
		}
		sort(line+1,line+num+1);
		sort(stack+1,stack+top+1);
		top=unique(stack+1,stack+top+1)-stack-1;
		work();
	}
}
int main(){
	k=read();n=read();
	if(k==1)one::main();
	else two::main();
    return 0;
}

 

posted @ 2018-09-16 21:09  符拉迪沃斯托克  阅读(198)  评论(0编辑  收藏  举报
Live2D