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;
    }
    
  • 相关阅读:
    稳扎稳打Silverlight(13) 2.0交互之鼠标事件和键盘事件
    稳扎稳打Silverlight(17) 2.0数据之详解DataGrid, 绑定数据到ListBox
    再接再厉VS 2008 sp1 + .NET 3.5 sp1(2) Entity Framework(实体框架)之详解 Linq To Entities 之一
    稳扎稳打Silverlight(8) 2.0图形之基类System.Windows.Shapes.Shape
    稳扎稳打Silverlight(11) 2.0动画之ColorAnimation, DoubleAnimation, PointAnimation, 内插关键帧动画
    稳扎稳打Silverlight(21) 2.0通信之WebRequest和WebResponse, 对指定的URI发出请求以及接收响应
    稳扎稳打Silverlight(16) 2.0数据之独立存储(Isolated Storage)
    稳扎稳打Silverlight(9) 2.0画笔之SolidColorBrush, ImageBrush, VideoBrush, LinearGradientBrush, RadialGradientBrush
    稳扎稳打Silverlight(23) 2.0通信之调用WCF的双向通信(Duplex Service)
    游戏人生Silverlight(1) 七彩俄罗斯方块[Silverlight 2.0(c#)]
  • 原文地址:https://www.cnblogs.com/lokiii/p/8821956.html
Copyright © 2011-2022 走看看