【BZOJ4071】八邻旁之桥(线段树)

【BZOJ4071】八邻旁之桥(线段树)

题面

BZOJ权限题,洛谷链接

题解

既然\(k<=2\)
那么,突破口就在这里

分类讨论
\(k=1\)
这。。。不就是中位数吗。。。。
直接把所有起点重点排个序,
算下中位数就行啦
\(k=2\)
似乎不好搞了
orz ZSY Dalao
我太弱了
我就是一个Vegetable Chicken
ZSY看一眼就会做

补充:ZSY大佬提醒我,Bridge我写错了
所以:#define Brige Bridge

首先,我们来看一看,如果有两座桥,
一个人会怎么动呢?
如果桥在他所移动的横向区间内
那么,一定会过这座桥,距离为\(dis(Qi-Ti)+1\)
如果,没有桥在他的区间内
他就要先走到桥,再从桥走过来
此时距离为\(abs(Qi-Brige)+abs(Ti-Brige)+1\)
这个东西再结合图像化个简
等于\(2abs(\frac{Qi+Ti}{2}-Brige)+1\)
所以,这个人走的桥一定是离\(\frac{Qi+Ti}{2}\)较近的桥

因此,把所有人按照\(\frac{Qi+Ti}{2}\)排序之后
开始枚举在哪个位置割开
然后左边的都走左边的桥
右边的都走右边的桥
拆成了两边之后就是\(k=1\)的情况了
但是因为是动态维护区间的中位数
所以要找个东西来维护
权值线段树,平衡树都是可以的

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define MAX 250000
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
struct Node{int a,b;}w[MAX];
bool operator<(Node a,Node b){return a.a+a.b<b.a+b.b;} 
int cnt;
long long ans;
int K,n,a[MAX],b[MAX],S[MAX],top;
struct SegMentTree
{
	struct node
	{
		int size;ll sum;
	}t[MAX<<2];
	int Kth(int now,int l,int r,int k)
		{
			if(l==r)return l;
			int mid=(l+r)>>1;
			if(k<=t[lson].size)return Kth(lson,l,mid,k);
			else return Kth(rson,mid+1,r,k-t[lson].size);
		}
	void Modify(int now,int l,int r,int pos,int ww)
		{
			t[now].size+=ww;t[now].sum+=1ll*ww*S[pos];
			if(l==r)return;
			int mid=(l+r)>>1;
			if(pos<=mid)Modify(lson,l,mid,pos,ww);
			else Modify(rson,mid+1,r,pos,ww);
		}
	ll QueryV(int now,int l,int r,int al,int ar)
		{
			if(al<=l&&r<=ar)return t[now].sum;
			int mid=(l+r)>>1;ll ret=0;
			if(al<=mid)ret+=QueryV(lson,l,mid,al,ar);
			if(ar>mid)ret+=QueryV(rson,mid+1,r,al,ar);
			return ret;
		}
	int QueryS(int now,int l,int r,int al,int ar)
		{
			if(al<=l&&r<=ar)return t[now].size;
			int mid=(l+r)>>1,ret=0;
			if(al<=mid)ret+=QueryS(lson,l,mid,al,ar);
			if(ar>mid)ret+=QueryS(rson,mid+1,r,al,ar);
			return ret;
		}
}T[2];
int main()
{
	K=read();n=read();
	char ch[2];
	if(K==1)
	{
		int tot=0;
		for(int i=1;i<=n;++i)
		{
			scanf("%s",ch);int p=ch[0]-'A';
			int s=read();
			scanf("%s",ch);int q=ch[0]-'A';
			int t=read();
			if(p==q){ans+=abs(s-t);continue;}
			else if(p==1)swap(s,t);
			++tot;a[tot]=s;b[tot]=t;S[++top]=s;S[++top]=t;
		}
		sort(&S[1],&S[top+1]);
		int G=S[top/2];
		for(int i=1;i<=top;++i)ans+=abs(G-S[i]);
		printf("%lld\n",ans+tot);
		return 0;
	}
	for(int i=1;i<=n;++i)
	{
		scanf("%s",ch);int p=ch[0]-'A';
		int s=read();
		scanf("%s",ch);int q=ch[0]-'A';
		int t=read();
		if(p==q){ans+=abs(s-t);continue;}
		ans++;S[++top]=s;S[++top]=t;
		if(s>t)swap(s,t);
		w[++cnt]=(Node){s,t};
	}
	if(!cnt){printf("%lld\n",ans);return 0;}
	sort(&w[1],&w[cnt+1]);
	sort(&S[1],&S[top+1]);
	top=unique(&S[1],&S[top+1])-S-1;
	for(int i=1;i<=cnt;++i)
	{
		w[i].a=lower_bound(&S[1],&S[top+1],w[i].a)-S;
		w[i].b=lower_bound(&S[1],&S[top+1],w[i].b)-S;
		T[1].Modify(1,1,top,w[i].a,1);
		T[1].Modify(1,1,top,w[i].b,1);
	}
	long long sum=1e18;
	for(int i=1;i<=cnt;++i)
	{
		T[0].Modify(1,1,top,w[i].a,1);
		T[0].Modify(1,1,top,w[i].b,1);
		T[1].Modify(1,1,top,w[i].a,-1);
		T[1].Modify(1,1,top,w[i].b,-1);
		int p1=T[0].Kth(1,1,top,i);//找中位数
		int p2=T[1].Kth(1,1,top,cnt-i);
		long long D0=0;
		D0+=1ll*T[0].QueryS(1,1,top,1,p1)*S[p1]-T[0].QueryV(1,1,top,1,p1);
		D0+=T[0].QueryV(1,1,top,p1,top)-1ll*T[0].QueryS(1,1,top,p1,top)*S[p1];
		long long D1=0;
		D1+=1ll*T[1].QueryS(1,1,top,1,p2)*S[p2]-T[1].QueryV(1,1,top,1,p2);
		D1+=T[1].QueryV(1,1,top,p2,top)-1ll*T[1].QueryS(1,1,top,p2,top)*S[p2];
		sum=min(sum,D0+D1);
	}
	printf("%lld\n",ans+sum);
	return 0;
}

posted @ 2018-01-05 21:52  小蒟蒻yyb  阅读(244)  评论(3编辑  收藏  举报