zoukankan      html  css  js  c++  java
  • LuoGuP4331:[BOI2004]Sequence 数字序列

    Pre

    前前后后调试了四个小时

    Solution

    考虑当前一段序列与前面一段序列的中位数,递增则入栈,否则合并后取中位数再入栈。

    正确性不会证明。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1000000 + 5;
    int n;
    inline int abs(int x){return x<0?-x:x;}
    struct Lef {
    	int fa[N], ch[N][2], dis[N], val[N], sz[N];
    	inline int Find (int x) {
    		int pre = x;
    		while (fa[pre] != pre) {pre = fa[pre];}
    		while (x != pre) {
    			int u = fa[x];
    			fa[x] = pre;
    			x = u;
    		}
    		return pre;
    	}
    	inline int merge (int x, int y) {
    		if (!x || !y) {return x + y;}
    		if (x == y) {return x;}
    		if (val[x] < val[y]) {swap (x, y);}
    		ch[x][1] = merge (ch[x][1], y);
    		fa[ch[x][1]] = x;
    		sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
    		if (dis[ch[x][1]] > dis[ch[x][0]]) {swap (ch[x][1], ch[x][0]);}
    		dis[x] = dis[ch[x][1]] + 1;
    		return x;
    	}
    	inline int del (int x) {
    		int y = merge (ch[x][0], ch[x][1]);
    		fa[y] = y;
    		fa[x] = y;
    		ch[x][0] = ch[x][1] = sz[x] = 0;
    		return y;
    	}
    }tree;
    int mip[N], top, id[N], L[N], stk[N], ans[N];
    inline void solve () {
    	for (int i = 1; i <= n; ++i) {
    		id[i] = i;
    		int tmp = i;
    		while (top && mip[top] > tree.val[tree.Find(id[i])]) {
    			tree.merge(tree.Find(id[stk[top]]), tree.Find(id[i]));
    			tmp = L[top];
    			int sz = (i - L[top] + 1 + 1) / 2;
    			int ttmp = id[i];
    			while (tree.sz[tree.Find(ttmp)] > sz) {
    				ttmp = tree.del(tree.Find(ttmp));
    			}
    			id[i] = ttmp;
    			top--;
    		}
    		top++;
    		mip[top] = tree.val[tree.Find(id[i])];
    		stk[top] = i;
    		L[top] = tmp;
    	}
    	long long tot = 0;
    	int now = 1;
    	for (int i = 1; i <= n; ++i) {
    		while (now != top && i >= L[now + 1]) {
    			now++;
    		}
    		ans[i] = mip[now];
    		tot += abs (mip[now] - tree.val[i]);
    	}
    	printf ("%lld
    ", tot);
    	for (int i = 1; i <= n; ++i) {
    		printf ("%d ", ans[i] + i);
    	}
    }
    int main () {
    	scanf ("%d", &n);
    	for (int i = 1; i <= n; ++i) {tree.fa[i] = i; tree.sz[i] = 1;}
    	for (int i = 1; i <= n; ++i) {scanf ("%d", &tree.val[i]); tree.val[i] -= i;}
    	solve ();
    	return 0;
    }
    

    Conclusion

    不错的一道考察乱搞能力的题目。

  • 相关阅读:
    Ubuntu中开启Telnet服务
    单片机串口通讯RXD与TXD如何对接详解
    KEIL, a Smart Comliler
    linux mail 命令(转载)
    VC程序在没装VC的机器中运行
    srand()以及rand()函数用法
    VC菜菜鸟:基于CFree的HelloWorld程序
    Keil使用中的若干问题(转)
    VMWARE 重新安装出错
    Linux个人学习笔记(编辑中)
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11248851.html
Copyright © 2011-2022 走看看