突然發現幾月前刷的此題
本着刷道水題的想法我就用treap虐了它一遍
題目描述:
促銷活動遵循以下原則:“參與本活動的顧客,應將自己的個人信息寫在所付帳單背面,
並將賬單投入指定的箱子。在每天的銷售結束後,箱子中消費金額最大和最小的兩張賬單將
被選出。消費最多的顧客將得到一筆獎金,獎金的數目等於兩張賬單金額之差。爲了避免因
爲一次消費而得到多筆獎金,依照以上原則選出的兩張賬單將不會被放回到箱子中,但箱子
裏剩下的賬單可以繼續參加第二天的活動。”
你的任務是根據每天投入箱子的所有帳單,計算出整個促銷活動中找是要付出的獎金總
額。本題中約定:
1. 整個出銷活動持續了 N 天,N≤5000。
2. 第 i 天放入的鈔票有 a[i]張,a[i]≤10^5,且 S=Σa[i]≤10^6。
3. 第 i 天放入的鈔票面值分別是 bi[1],bi[2],…,bi[a[i]],b[j] ≤10^6。
輸入格式:
輸入文件的第一行的正整數 N 表示爲此次促銷活動持續的天數。接下來的 N 行含有一連
串用單個空格隔開的非負數。第 I+1 行的數字表示在第 I 天促銷活動中放入投票箱內帳單的
價格。此行的第一個整數 K 表示這一天放入投票箱內的帳單數,接着的 K 個正整數分別代表
着每張帳單的價格。
輸出格式:
輸出文件中恰含有一整數,它的值等於此次促銷活動用作獎勵的總花費。
樣例:
pro.in:
5
3 1 2 3
2 1 1
4 10 5 5 1
0
1 2
pro.out:
19
trep code
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
#define Rand() (rand () * rand () * rand () % 10000000)
const int maxn = 1000000 + 5;
class Treap_tree
{
public :
Treap_tree()
{
e = root = tot = 0;
}
void Left_Rotate(int &rt)
{
int y = Right[rt];
Right[rt] = Left[y];
Left[y] = rt;
rt = y;
}
void Right_Rotate(int &rt)
{
int y = Left[rt];
Left[rt] = Right[y];
Right[y] = rt;
rt = y;
}
void Insert(int &rt, int y)
{
if (!rt)
{
++e;
Left[e] = Right[e] = 0;
Fix[e] = Rand();
Value[e] = y;
rt = e;
}
else
{
if (y < Value[rt])
{
Insert(Left[rt], y);
if (Fix[Left[rt]] > Fix[rt]) Right_Rotate(rt);
}
else if ( y >= Value[rt])
{
Insert(Right[rt], y);
if (Fix[Right[rt]] > Fix[rt]) Left_Rotate(rt);
}
}
}
void Search_Max(int &rt)
{
if (Right[rt])
Search_Max(Right[rt]);
else
{
MAX = Value[rt];
rt = Left[rt];
}
}
void Search_Min(int &rt)
{
if (Left[rt])
Search_Min(Left[rt]);
else
{
MIN = Value[rt];
rt = Right[rt];
}
}
long long work()
{
cin >> n;
for (int i=1; i<=n; ++i)
{
int x, y;
scanf("%d", &x);
for (int j=1; j<=x; ++j)
{
scanf("%d", &y);
Insert(root, y);
}
Search_Max(root);
if (!root)
MIN = MAX;
else
Search_Min(root);
tot += MAX - MIN;
}
return tot;
}
private :
int MAX, MIN;
int n, e, root;
long long tot;
int Left[maxn], Right[maxn], Fix[maxn], Value[maxn];
};
Treap_tree treap;
int main()
{
srand((unsigned)time(0));
freopen("pro.in", "r", stdin);
freopen("pro.out", "w", stdout);
cout << treap.work();
return 0;
}
不過此題平衡樹常數註定常數很大 70分能拿到
其他的方法是hash or 分段hash
1.hash 複雜度是O(S + NM) M爲最大數字
2.分段hash 複雜度O(S + N*M^(1/2))
分段hash是此題正解
但用hash我的數據也可AC
我的hash巧妙在每次操作記錄了當前Min, Max;
讀入時也適當更新
接着掃描則可優化較多了
hash code
#include <cmath>
#include <cstdio>
#include <climits>
#include <cstdlib>
#include <iostream>
using namespace std;
#define maxn 1000005
int n;
int hash[maxn];
__int64 tot = 0;
int Min = INT_MAX, Max = -INT_MAX;
int main()
{
int x,y;
freopen("pro.in", "r", stdin);
freopen("pro.out", "w", stdout);
scanf("%d", &n);
for (int i=1; i<=n; i++)
{
scanf("%d", &x);
for (int j=1;j<=x;j++)
{
scanf("%d",&y);
++hash[y];
Min = (Min > y) ? y : Min;
Max = (Max < y) ? y : Max;
}
if (!hash[Max])
{
for (int j=Max-1; j>=1; --j)
if (hash[j]) { Max=j; break; }
}
if (!hash[Min])
{
for (int j=Min+1; j<=maxn; ++j)
if (hash[j]) { Min=j;break; }
}
tot += Max - Min;
hash[Max]--; hash[Min]--;
}
printf("%I64d", tot);
return 0;
}
數據奉上
http://pan.baidu.com/share/link?shareid=22451&uk=2652110486