zoukankan      html  css  js  c++  java
  • [bzoj1112][POI2008]砖块Klo_非旋转Treap

    砖块Klo bzoj-1112 POI-2008

    题目大意:$N$柱砖,希望有连续$K$柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

    注释:$1le kle nle 10^5$,$0le height_ile 10^6$。


    想法:

    如果我们想让以$i$为左端点的连续$k$柱合法,

    假设最后的高度是$H$,那么我们的代价就是:

    $sumlimits_{j=i}^{i+k-1} |h_j-H|$。

    显然当$H$为这$k$个数的中位数的时候当前区间的代价最小。

    至此,我们就可以弄一个平衡树。

    每次加入$i+k$然后把开头的$i$删去,求出当前区间的中位数更新答案即可。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010 
    using namespace std; typedef long long ll;
    struct Node
    {
    	int ls,rs,size; ll sum,val,key;
    }a[N];
    struct par {int x,y;};
    ll num[N]; int root,cnt;
    inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
    ll rd() {ll x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
    inline int newnode(ll val)
    {
    	int x=++cnt;
    	a[x].size=1; a[x].ls=a[x].rs=0;
    	a[x].val=a[x].sum=val; a[x].key=rand()*rand();
    	return x;
    }
    inline void pushup(int x)
    {
    	int ls=a[x].ls,rs=a[x].rs;
    	a[x].size=1; a[x].sum=a[x].val;
    	if(ls) a[x].size+=a[ls].size,a[x].sum+=a[ls].sum;
    	if(rs) a[x].size+=a[rs].size,a[x].sum+=a[rs].sum;
    }
    int merge(int x,int y)
    {
    	if(!x||!y) return x|y;
    	if(a[x].key>a[y].key)
    	{
    		a[x].rs=merge(a[x].rs,y); pushup(x);
    		return x;
    	}
    	else
    	{
    		a[y].ls=merge(x,a[y].ls); pushup(y);
    		return y;
    	}
    }
    par split(int x,int k)
    {
    	if(!k) return (par){0,x};
    	int ls=a[x].ls,rs=a[x].rs;
    	if(k==a[ls].size)
    	{
    		a[x].ls=0; pushup(x);
    		return (par){ls,x};
    	}
    	else if(k==a[ls].size+1)
    	{
    		a[x].rs=0; pushup(x);
    		return (par){x,rs};
    	}
    	else if(k<a[ls].size)
    	{
    		par t=split(ls,k);
    		a[x].ls=t.y; pushup(x);
    		return (par){t.x,x};
    	}
    	else
    	{
    		par t=split(rs,k-a[ls].size-1);
    		a[x].rs=t.x; pushup(x);
    		return (par){x,t.y};
    	}
    }
    par split_val(int x,int val)
    {
    	if(!x) return (par){0,x};
    	int ls=a[x].ls,rs=a[x].rs;
    	if(a[x].val>=val)
    	{
    		par t=split_val(ls,val);
    		a[x].ls=t.y; pushup(x);
    		return (par){t.x,x};
    	}
    	else
    	{
    		par t=split_val(rs,val);
    		a[x].rs=t.x; pushup(x);
    		return (par){x,t.y};
    	}
    }
    void delet(ll val)
    {
    	par t1=split_val(root,val),t2=split(t1.y,1);
    	root=merge(t1.x,t2.y);
    }
    void insert(ll val)
    {
    	par t1=split_val(root,val);
    	root=merge(t1.x,merge(newnode(val),t1.y));
    }
    void output(int x)
    {
    	int ls=a[x].ls,rs=a[x].rs;
    	if(ls) output(ls);
    	printf("%lld ",a[x].val);
    	if(rs) output(rs);
    }
    int main()
    {
    	srand(12378);
    	int n=rd(),k=rd(); for(int i=1;i<=n;i++) num[i]=rd();
    	for(int i=1;i<=k;i++) insert(num[i]);
    	int id=(k+1)/2;
    	par t1=split(root,id-1),t2=split(t1.y,1);
    	ll ans=(a[t2.x].val*a[t1.x].size-a[t1.x].sum)+(a[t2.y].sum-a[t2.x].val*a[t2.y].size);
    	int dic=k,dic_val=a[t2.x].val;
    	root=merge(t1.x,merge(t2.x,t2.y));
    	for(int i=k+1;i<=n;i++)
    	{
    		insert(num[i]); delet(num[i-k]);
    		// printf("%d : ",i); output(root); puts("");
    		par t1=split(root,id-1),t2=split(t1.y,1);
    		ll now=(a[t2.x].val*a[t1.x].size-a[t1.x].sum)+(a[t2.y].sum-a[t2.x].val*a[t2.y].size);
    		if(now<ans) dic=i,ans=now,dic_val=a[t2.x].val;
    		root=merge(t1.x,merge(t2.x,t2.y));
    	}
    	for(int i=dic-k+1;i<=dic;i++) num[i]=dic_val;
    	printf("%lld
    ",ans);
    	// for(int i=1;i<=n;i++) printf("%lld
    ",num[i]);
    	// puts("");
    	return 0;
    }
    

     小结:平衡树的应用还是较为广泛的。

  • 相关阅读:
    关于C++中操作符重载的疑问 :四个运算符=, ->, [], ()不可以重载为全局函数(友员函数)...
    linux内核移植过程问题总结
    关于开发板用tftp下载失败分析
    阿里云ECS下安装的MySQL无法远程连接?
    uva729
    使用 Confluence 6 服务器移动应用
    Confluence 6 移动浏览查看任务
    Confluence 6 移动浏览查看通知
    Confluence 6 移动浏览查看页面,博客和评论
    Confluence 6 移动浏览搜索内容和人
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10235065.html
Copyright © 2011-2022 走看看