zoukankan      html  css  js  c++  java
  • bzoj 4071: [Apio2015]巴邻旁之桥【splay】

    用权值线段树会容易一些并快一些,但是想复健一下splay所以打了splay
    然后果然不会打了。
    解题思路:
    首先把家和办公室在同一侧的提出来直接加进答案里;
    对于k=1,直接选所有办公室和家的中位数即可,因为显然如果选的点两边的办公室和家的点不一样多的话,显然可以向多的一侧移动来使得总路程减少;
    对于k=2,所有人按家和办公室的中点排序,然后显然有一个断点,左边的人走左边的桥,右边的人走右边的桥。因为选择距离中点近的桥一定不会变差。然后枚举这个断点,先从左到右依次加进去,每次加完之后把当前在splay里的这部分答案(中位数和其他数的差得绝对值)存起来,然后从左到右依次删掉,此时splay里的是除了1~i的部分,把这部分的答案加上之前存起来的答案就是最后答案,然后在这些答案里取min即可。
    !这里因为取min所以初始值设为inf了,注意特判一下没有家和办公室在两岸的人把初始值改成0
    splay注意事项:如果涉及插入,要先插两个辅助点inf,-inf进去,涉及删除则要插四个;

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int N=200005;
    const long long inf=1e15;
    int k,n,top,root,tot;
    long long q[N],ans;
    struct qwe
    {
    	int s,t,m;
    	qwe(int S=0,int T=0,int M=0)
    	{
    		s=S,t=T,m=M;
    	}
    }a[N];
    struct Splay
    {
    	int f,c[2],s;
    	long long sum,v;
    }t[N];
    inline bool cmp(const qwe &a,const qwe &b)
    {
    	return a.m<b.m;
    }
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    inline void ud(int x)
    {
    	t[x].s=t[t[x].c[0]].s+t[t[x].c[1]].s+1;
    	t[x].sum=t[t[x].c[0]].sum+t[t[x].c[1]].sum+(long long)t[x].v;
    }
    void zhuan(int x,int &k)
    {
    	int y=t[x].f,z=t[y].f,l=t[y].c[0]!=x,r=l^1;
    	if(y!=k)
    		t[z].c[t[z].c[0]!=y]=x;
    	else
    		k=x;
    	t[x].f=z;
    	t[y].c[l]=t[x].c[r];
    	t[t[y].c[l]].f=y;
    	t[x].c[r]=y;
    	t[y].f=x;
    	ud(y);
    	ud(x);
    }
    void splay(int x,int &k)
    {
    	while(x!=k)
    	{
    		int y=t[x].f,z=t[y].f;
    		if(y!=k)
    		{
    			if((t[y].c[0]==x)^(t[z].c[0]==y))
    				zhuan(x,k);
    			else
    				zhuan(y,k);
    		}
    		zhuan(x,k);
    	}
    }
    int paiming(int x,int va)
    {
    	int r=0;
    	while(x)
    	{
    		if(t[x].v>va)
    			x=t[x].c[0];
    		else
    			r+=t[t[x].c[0]].s+1,x=t[x].c[1];
    	}
    	return r;
    }
    int shu(int x,int k)
    {
    	if(!x)
    		return 0;
    	if(t[t[x].c[0]].s+1==k)
    		return x;
    	else if(t[t[x].c[0]].s>=k)
    		return shu(t[x].c[0],k);
    	else
    		return shu(t[x].c[1],k-t[t[x].c[0]].s-1);
    }
    void charu(int k)
    {
    	int x=shu(root,paiming(root,k));
    	splay(x,root);
    	int y=shu(t[x].c[1],1);
    	splay(y,t[x].c[1]);
    	t[y].c[0]=++tot;
    	t[tot].f=y;
    	t[tot].v=k;
    	t[tot].sum=k;
    	t[tot].s=1;
    	ud(y);
    	ud(x);
    }
    void shanchu(int k)
    {
    	int x=shu(root,paiming(root,k)-1);//cerr<<k<<" "<<paiming(root,k)<<endl;
    	splay(x,root);
    	int y=shu(t[x].c[1],2);
    	splay(y,t[x].c[1]);
    	t[t[y].c[0]].f=0;
    	t[y].c[0]=0;
    	ud(y);
    	ud(x);
    }
    long long ques(int x)
    {//cerr<<t[x].v<<" ";
    	splay(x,root);
    	return 1ll*t[x].v*(t[t[x].c[0]].s-2)-t[t[x].c[0]].sum+t[t[x].c[1]].sum-1ll*t[x].v*(t[t[x].c[1]].s-2)-4*inf;
    }
    int main()
    {
    	k=read(),n=read();
    	for(int i=1;i<=n;i++)
    	{
    		char c1=0,c2=0;
    		while(c1!='A'&&c1!='B')
    			c1=getchar();
    		int x=read();
    		while(c2!='A'&&c2!='B')
    			c2=getchar();
    		int y=read();//cerr<<c1<<" "<<c2<<" "<<x<<" "<<y<<endl;
    		if(c1==c2)
    			ans+=abs(y-x);
    		else
    			a[++top]=qwe(x,y,abs(x+y)>>1);
    	}
    	n=top;
    	if(k==1)
    	{
    		int e[N];
    		for(int i=1;i<=n;i++)
    			e[i]=a[i].s,e[i+n]=a[i].t;
    		sort(e+1,e+1+n*2);
    		int p=e[n];
    		for(int i=1;i<=n*2;i++)
    			ans+=1ll*abs(e[i]-p);
    		printf("%lld
    ",ans+n);
    		return 0;
    	}
    	sort(a+1,a+1+n,cmp);
    	tot=4;
    	t[1].v=-inf,t[1].s=4,t[1].c[0]=2,t[1].c[1]=3,root=1;
    	t[2].v=-inf,t[2].sum=-inf,t[2].s=1,t[2].f=1;
    	t[3].v=inf,t[3].sum=2ll*inf,t[3].s=2,t[3].f=1,t[3].c[1]=4;
    	t[4].v=inf,t[4].sum=inf,t[4].s=1,t[4].f=3;
    	for(int i=1;i<=n;i++)
    	{
    		charu(a[i].s),charu(a[i].t);
    		q[i]=ques(shu(root,i+2));//cerr<<q[i]<<endl;
    	}//cerr<<"ok"<<endl;
    	long long sum=inf;
    	if(!n)
    		sum=0;
    	for(int i=1;i<=n;i++)
    	{
    		shanchu(a[i].s),shanchu(a[i].t);
    		sum=min(sum,q[i]+ques(shu(root,n-i+2)));
    	}
    	printf("%lld
    ",ans+sum+n);
    	return 0;
    }
    
  • 相关阅读:
    bzoj4758: [Usaco2017 Jan]Subsequence Reversal(区间dp)
    bzoj4580: [Usaco2016 Open]248(区间dp)
    1617: [Usaco2008 Mar]River Crossing渡河问题(dp)
    bzoj21012101: [Usaco2010 Dec]Treasure Chest 藏宝箱(滚动数组优化dp)
    P2339 提交作业usaco(区间dp)
    day11
    bzoj2330: [SCOI2011]糖果(差分约束)
    P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm(Tarjan+记忆化)
    P2700逐个击破(并查集/树形dp)
    bzoj1770: [Usaco2009 Nov]lights 燈(折半搜索)
  • 原文地址:https://www.cnblogs.com/lokiii/p/8821956.html
Copyright © 2011-2022 走看看