• 【bzoj1588】 HNOI2002—营业额统计


    http://www.lydsy.com/JudgeOnline/problem.php?id=1588 (题目链接)

    题意

      给出一个序列,对于每一个数,找出之前与它相差最小的数,两者相减取绝对值加入答案。

    Solution1

      这道题只有单点插入和查询前驱后继的操作,其实完全可以set水过去,算了就当splay练手吧。。

      这道题要求splay满足二叉搜索树的性质,而对序列的顺序没有要求,于是我们每次在平衡树中插入一个节点,然后splay到根节点,因为平衡树满足二叉搜索树的性质,这样的话查询前驱和后继的时候就可以大大减少复杂度。

    代码

    // bzoj1588
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf (1<<30)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010;
    int fa[maxn],tr[maxn][2],val[maxn];
    int n,size,rt,t1,t2;
    
    void rotate(int x,int &k) {
    	int y=fa[x],z=fa[y],l,r;
    	if (tr[y][0]==x) l=0;else l=1;r=l^1;
    	if (k==y) k=x;
    	else tr[z][tr[z][1]==y]=x;
    	fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
    	tr[y][l]=tr[x][r];tr[x][r]=y;
    }
    void splay(int x,int &k) {
    	while (x!=k) {
    		int y=fa[x],z=fa[y];
    		if (y!=k) {
    			if (tr[y][0]==x ^ tr[z][0]==y) rotate(x,k);
    			else rotate(y,k);
    		}
    		rotate(x,k);
    	}
    }
    bool insert(int &k,int x,int f) {
    	if (k==0) {k=++size;val[k]=x,fa[k]=f,splay(k,rt);return 1;}
    	if (val[k]==x) return 0;
    	if (x<val[k]) return insert(tr[k][0],x,k);
    	else return insert(tr[k][1],x,k);
    }
    void query_pr(int k) {
    	if (tr[k][0]==0) return;
    	k=tr[k][0];
    	while (tr[k][1]) k=tr[k][1];
    	t1=val[k];
    }
    void query_nx(int k) {
    	if (tr[k][1]==0) return;
    	k=tr[k][1];
    	while (tr[k][0]) k=tr[k][0];
    	t2=val[k];
    }
    int main() {
    	scanf("%d",&n);
    	int ans=0;
    	for (int x,i=1;i<=n;i++) {
    		scanf("%d",&x);
    		if (!insert(rt,x,0)) continue;
    		t1=-inf;t2=inf;
    		query_pr(rt);
    		query_nx(rt);
    		if (i==1) ans+=x;
    		else ans+=min(x-t1,t2-x);
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    UPD:

    solution2

      双向链表,来自2016NOIP初赛补全代码T1的思路。。。完爆splay啊。。

    细节

      快排的cmp函数的<改成<=就迷之RE。。

    代码

    // bzoj1588
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010;
    int nxt[maxn],pre[maxn],a[maxn],rank[maxn];
    int n;
    
    int cmp(int x,int y) {
    	return a[x]<a[y];
    }
    int main() {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) {
    		scanf("%d",&a[i]);
    		rank[i]=i;
    	}
    	sort(rank+1,rank+1+n,cmp);
    	for (int i=1;i<=n;i++) {
    		pre[rank[i]]=rank[i-1];
    		nxt[rank[i]]=rank[i+1];
    	}
    	int ans=0;
    	for (int i=n;i>=2;i--) {
    		int l=inf,r=inf;
    		if (pre[i]!=0) l=a[i]-a[pre[i]];
    		if (nxt[i]!=0) r=a[nxt[i]]-a[i];
    		ans+=min(l,r);
    		nxt[pre[i]]=nxt[i];
    		pre[nxt[i]]=pre[i];
    	}
    	printf("%d",ans+a[1]);
    	return 0;
    }
    

      

      

  • 相关阅读:
    敏捷不是XP(口水文)
    利用异或的特性解决,找出重复数的问题,应该是目前最优算法。
    开源和免费那些事儿(二)
    开源和免费那些事儿
    LINQ本质 外篇 JOIN补遗
    在北京求.NET开发职位,人已经到达北京
    软件是邪恶的
    最近遇到的两个面试题兼卖身广告
    谈谈信仰和银弹。
    继续高阶函数好玩有用的扩展(网吧行文)
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5939351.html
Copyright © 2020-2023  润新知