zoukankan      html  css  js  c++  java
  • 【题解】巴邻旁之桥

    Problem

    ( ext{Solution:})

    (k=1)的时候,中位数就可以解决问题。

    这引起思考:(k=2)是不是一个拓展版?

    考虑无论将线段按照左还是右端点排序都不能满足要求,于是我们发现:当桥靠近一个线段的中点的时候,走它一定会优。

    所以,我们将线段按照中点排序,并考虑枚举分界点,这样左右两边就被划分成了两个(k=1)的子问题。

    这是个动态的求中位数问题。考虑 FHQ_Treap 解决。

    维护两棵树,以坐标为序,一颗维护分界点左边的,一颗维护分界点右边的。这样我们只需要统计出每次的答案就可以了。

    那如何统计答案?

    将点画在坐标轴上,观察发现:要求它们到一条线的距离,只需要:求出线右边所有坐标到线的距离 加上 线左边所有坐标到线的距离 即可。

    那么以值为序的同时,我们可以维护 siz 和 sum 来实现这一点。

    关键在于:思考到拓展思路并理解按照中点排序的意义 以及 如何快速统计答案。

    总之,画个图很重要。

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=3e5+10;
    inline int read() {
    	int s=0;
    	char ch=getchar();
    	while(!isdigit(ch))ch=getchar();
    	while(isdigit(ch)) {
    		s=s*10-48+ch;
    		ch=getchar();
    	}
    	return s;
    }
    inline void write(long long x){
    	if(x<0)putchar('-');
    	if(x>9)write(x/10);
    	putchar(x%10+48); 
    }
    struct Line {
    	int s,t,mid;
    	bool operator<(const Line&B)const {
    		return mid<B.mid;
    	}
    };
    vector<Line>v;
    inline int rd() {
    	return rand()<<15|rand();
    }
    struct Tree {
    	int cnt,rt,siz[MAXN],tr[MAXN][2],cv[MAXN];
    	int val[MAXN];
    	long long sum[MAXN];
    	inline int build(int v) {
    		siz[++cnt]=1;
    		cv[cnt]=rd();
    		val[cnt]=v;
    		sum[cnt]=v;
    		return cnt;
    	}
    	inline void pushup(int x) {
    		siz[x]=siz[tr[x][1]]+siz[tr[x][0]]+1;
    		sum[x]=sum[tr[x][1]]+sum[tr[x][0]]+val[x];
    	}
    	int merge(int x,int y) {
    		if(!x||!y)return x+y;
    		if(cv[x]<cv[y]) {
    			tr[x][1]=merge(tr[x][1],y);
    			pushup(x);
    			return x;
    		} else {
    			tr[y][0]=merge(x,tr[y][0]);
    			pushup(y);
    			return y;
    		}
    	}
    	void split(int now,int k,int &x,int &y) {
    		if(!now) {
    			x=y=0;
    			return;
    		}
    		if(val[now]<=k)x=now,split(tr[now][1],k,tr[now][1],y);
    		else y=now,split(tr[now][0],k,x,tr[now][0]);
    		pushup(now);
    	}
    	int kth(int now,int k) {
    		if(k<=siz[tr[now][0]])return kth(tr[now][0],k);
    		else if(k==siz[tr[now][0]]+1)return val[now];
    		else return kth(tr[now][1],k-siz[tr[now][0]]-1);
    	}
    	void Ins(int v) {
    		int x,y;
    		split(rt,v,x,y);
    		rt=merge(merge(x,build(v)),y);
    	}
    	void del(int v){
    		int x,y,z;
    		split(rt,v,x,y);
    		split(x,v-1,x,z);
    		z=merge(tr[z][0],tr[z][1]);
    		rt=merge(merge(x,z),y);
    	}
    } T[2];
    int K,N;
    long long ans;
    long long res[MAXN];
    char P[2],Q[2];
    inline int Abs(int x) {
    	if(x<0)x=-x;
    	return x;
    }
    inline int Min(int x,int y) {return x-y>0?y:x;}
    inline long long Lmin(long long x,long long y){return x-y>0?y:x;}
    int main() {
    	K=read();
    	N=read();
    	for(int i=1; i<=N; ++i) {
    		char P,Q;
    		int x,y;
    		cin>>P>>x>>Q>>y;
    		if(P==Q) {
    			ans+=1ll*Abs(x-y);
    			continue;
    		} else {
    			if(x>y)swap(x,y);
    			Line S;
    			S.s=x;
    			S.t=y;
    			S.mid=x+y;
    			v.push_back(S);
    		}
    	}
    	ans+=(long long)v.size();
    	sort(v.begin(),v.end());
    	if((int)v.size()==0){
    		write(ans);putchar('
    ');
    		return 0;
    	}
    	if(K==1) {
    		vector<int>V;
    		for(int i=0; i<(int)v.size(); ++i)V.push_back(v[i].s),V.push_back(v[i].t),ans+=1ll*(v[i].t-v[i].s);
    		sort(V.begin(),V.end());
    		int All=(int)V.size();
    		All>>=1;
    		int pos=V[All];
    		for(int i=0; i<(int)v.size(); ++i) {
    			if(pos>=v[i].s&&pos<=v[i].t)continue;
    			long long dt=Min(Abs(pos-v[i].s),Abs(pos-v[i].t));
    			dt<<=1ll;
    			ans+=dt;
    		}
    		write(ans);putchar('
    ');
    		return 0;
    	} else {
    		for(int i=1; i<(int)v.size(); ++i) {
    			T[1].Ins(v[i].s);
    			T[1].Ins(v[i].t);
    		}
    		T[0].Ins(v[0].s);
    		T[0].Ins(v[0].t);
    		for(int i=1; i<(int)v.size()-1; ++i) {
    			T[1].del(v[i].s);
    			T[1].del(v[i].t);
    			T[0].Ins(v[i].s);
    			T[0].Ins(v[i].t);
    			int num=T[0].siz[T[0].rt];
    			num>>=1;
    			int v=T[0].kth(T[0].rt,num);
    			int Tx,Ty;
    			T[0].split(T[0].rt,v,Tx,Ty);
    			int lsiz=T[0].siz[Tx];
    			int rsiz=T[0].siz[Ty];
    			res[i]=1ll*lsiz*v-T[0].sum[Tx];
    			res[i]+=T[0].sum[Ty]-1ll*rsiz*v;
    			T[0].rt=T[0].merge(Tx,Ty);
    			num=T[1].siz[T[1].rt];
    			num>>=1;
    			v=T[1].kth(T[1].rt,num);
    			int TTx,TTy;
    			T[1].split(T[1].rt,v,TTx,TTy);
    			lsiz=T[1].siz[TTx];
    			rsiz=T[1].siz[TTy];
    			res[i]+=1ll*lsiz*v-T[1].sum[TTx];
    			res[i]+=T[1].sum[TTy]-1ll*rsiz*v;
    			T[1].rt=T[1].merge(TTx,TTy);
    		}
    		long long Ans=(1LL<<60);
    		for(int i=1;i<(int)v.size()-1;++i)Ans=Lmin(Ans,res[i]);
    		Ans+=ans;
    		write(Ans);putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    html5 audio vedio and video.js
    webpack的require是如何工作的?
    webpack HMR是如何工作的?
    vuejs code splitting with webpack 3种模式
    how webpack Hot Module Replacement works
    C# checkedlistbox 控件 有bug
    C# DataGridView 更改类型 重绘
    C# webapi
    C# 遍历控件名称
    C# 转json
  • 原文地址:https://www.cnblogs.com/h-lka/p/14923021.html
Copyright © 2011-2022 走看看