您的位置:首页 > 编程语言 > PHP开发

★【STL】报表统计

2012-04-18 08:40 155 查看
Description
小Q的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一。经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作: INSERT i k 在原数列的第i个元素后面添加一个新元素k; 如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子) MIN_GAP 查询相邻两个元素的之间差值(绝对值)的最小值 MIN_SORT_GAP 查询所有元素中最接近的两个元素的差值(绝对值) 例如一开始的序列为 5 3 1 执行操作INSERT 2 9将得到: 5 3 9 1 此时MIN_GAP为2,MIN_SORT_GAP为2。 再执行操作INSERT 2 6将得到: 5 3 9 6 1 注意这个时候原序列的第2个元素后面已经添加了一个9,此时添加的6应加在9的后面。这个时候MIN_GAP为2,MIN_SORT_GAP为1。于是小Q写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?
Input
第一行包含两个整数N,M,分别表示原数列的长度以及操作的次数。第二行为N个整数,为初始序列。接下来的M行每行一个操作,即“INSERT i k”,“MIN_GAP”,“MIN_SORT_GAP”中的一种(无多余空格或者空行)。
Output
对于每一个“MIN_GAP”和“MIN_SORT_GAP”命令,输出一行答案即可。
Sample Input
3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP
Sample Output
2
2
1
HINT

对于30%的数据,N ≤ 1000 , M ≤ 5000
对于100%的数据,N , M ≤500000
对于所有的数据,序列内的整数不超过5*108。
用一个STL multiset(g)维护当前列表中有哪些数,以便每插入一个数找到它的前驱和后继,从而更新MIN_SORT_GAP的答案。

再用一个STL nultiset(S)维护所有相邻的数的差,以便找到这个最小的差(MIN_GAP)并且还可保证插入一个数之后将原来已经不再相邻的结点的差值从S中删掉。

Accode:
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <cstring>
#include <set>
#include <cmath>

using std::multiset; using std::min;
const int maxN = 500010;
const int INF = 0x3f3f3f3f;
multiset <int> S, g;
multiset <int>::iterator iter;
int s[maxN][2]; char str[20];
//用s来记录初始列表以及在次插入的最后一个数,
//因为这时其余的数并不重要。
int Min[maxN], n, m, ans = INF;
//用Min记录每个列表内部的最小相邻差
//(即并不记录它的末尾与下一个列表的相邻差)。
bool flag = 1;

inline int getint()
{
int res = 0; char tmp; bool sgn = 1;
do tmp = getchar();
while (!isdigit(tmp) && tmp - '-');
if (tmp == '-') {tmp = getchar(); sgn = 0;}
do res = (res << 3) + (res << 1) + tmp - '0';
while (isdigit(tmp = getchar()));
return sgn ? res : -res;
} //数据中有负数,所以一定要考虑符号。

int main()
{
freopen("form.in", "r", stdin);
freopen("form.out", "w", stdout);
n = getint(); m = getint();
for (int i = 1; i < n + 1; Min[i++] = INF)
g.insert(s[i][1] = *s[i] = getint());
for (int tmp = *(iter = g.begin())++;
iter != g.end(); tmp = *iter++)
ans = min(ans, *iter - tmp);
for (int i = 1; i < n; ++i)
S.insert(abs(*s[i] - *s[i + 1]));
for (int i, x, tmp; m--; )
switch (scanf("%s", str), strlen(str))
{
case 6:
i = getint(), x = getint();
if (ans > 0)
//如果此时MIN_SORT_GAP的值已经等于0,
//那么以后都不再对g进行插入操作,直接回答即可。
{
if ((iter = g.lower_bound(x)) != g.end())
ans = min(ans, *iter - x);
//一定要保证x有后继才能更新。
if (iter != g.begin())
ans = min(ans, x - *--iter);
//一定要保证x有前驱才能更新。
g.insert(x);
}
if (flag)
//如果此时某一列表的Min值已经为0,
//那么就不插入直接输出询问结果。
{
if (i < n)
S.erase(S.find(abs(s[i][1] - *s[i + 1])));
//删除已经失效的元素相邻差。
//一定要保证i不为最后一个列表才进行次操作,
//并且只能删除S中的一个值。
if ((tmp = abs(x - s[i][1])) < Min[i])
{
if (Min[i] < INF)
S.erase(S.find(Min[i]));
//这句可以不要,但是为了效率可以加上。
S.insert(Min[i] = tmp);
} //更新该列表的Min值。
if (i < n)
S.insert(abs((s[i][1] = x) - *s[i + 1]));
//将新得到的该列表尾部与下一列表首部之差加入S,
//一定要保证i不为最后一个列表才进行此操作。
}
flag = flag && Min[i];
break;
case 7: printf("%d\n", *S.begin()); break;
case 12: printf("%d\n", ans); break;
}
return 0;
}

手打Size Balanced Tree(超时):

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 500010, INF = 0x3f3f3f3f;
class SBT
{
private:
int key[maxN << 2], sz[maxN << 2], T;
int lc[maxN << 2], rc[maxN << 2], tot;
void Zig(int &T)
{
int tmp = lc[T]; lc[T] = rc[tmp];
rc[tmp] = T; sz[tmp] = sz[T];
sz[T] = sz[lc[T]] + sz[rc[T]] + 1;
T = tmp; return;
}
void Zag(int &T)
{
int tmp = rc[T]; rc[T] = lc[tmp];
lc[tmp] = T; sz[tmp] = sz[T];
sz[T] = sz[lc[T]] + sz[rc[T]] + 1;
T = tmp; return;
}
void maintain(int &T, bool flag)
{
if (!T || !lc[T] && !rc[T]) return;
if (!flag)
{
if (sz[lc[lc[T]]] > sz[rc[T]]) Zig(T);
else if (sz[rc[lc[T]]] > sz[rc[T]])
{Zag(lc[T]); Zig(T);}
else return;
}
else
{
if (sz[rc[rc[T]]] > sz[lc[T]]) Zag(T);
else if (sz[lc[rc[T]]] > sz[lc[T]])
{Zig(rc[T]); Zag(T);}
else return;
}
maintain(lc[T], 0); maintain(rc[T], 1);
maintain(T, 0); maintain(T, 1);
return;
}
void Ins(int &T, int v)
{
if (!T)
{sz[T = ++tot] = 1; key[T] = v; return;}
++sz[T];
if (v < key[T]) Ins(lc[T], v);
else Ins(rc[T], v);
maintain(T, v >= key[T]);
return;
}
int Del(int &T, int v)
{
--sz[T];
if (v == key[T]
|| v < key[T] && !lc[T]
|| v > key[T] && !rc[T])
{
int tmp = key[T];
if (!lc[T] || !rc[T]) T = lc[T] + rc[T];
else key[T] = Del(lc[T], key[T]);
return tmp;
}
if (v < key[T]) return Del(lc[T], v);
else return Del(rc[T], v);
}
int pred(int &T, int v, int ans)
{
if (!T) return ans;
if (key[T] < v && key[T] > ans) ans = key[T];
if (v < key[T]) return pred(lc[T], v, ans);
else return pred(rc[T], v, ans);
}
int succ(int &T, int v, int ans)
{
if (!T) return ans;
if (!(key[T] < v) && key[T] < ans) ans = key[T];
if (v < key[T]) return succ(lc[T], v, ans);
else return succ(rc[T], v, ans);
}
int min(int T) {return lc[T] ? min(lc[T]) : key[T];}
int max(int T) {return rc[T] ? max(rc[T]) : key[T];}
public:
SBT(): tot(0), T(0)
{
memset(key, 0, sizeof key);
memset(lc, 0, sizeof lc);
memset(rc, 0, sizeof rc);
memset(sz, 0, sizeof sz);
}
void Ins(int v) {Ins(T, v); return;}
void Del(int v) {Del(T, v); return;}
int pred(int v) {return pred(T, v, ~INF);}
int succ(int v) {return succ(T, v, INF);}
int min() {return min(T);}
int max() {return max(T);}
} S, g; char str[20];
int s[maxN][2], Min[maxN], n, m, ans = INF;

inline int getint()
{
int res = 0; char tmp; bool sgn = 1;
do tmp = getchar();
while (!isdigit(tmp) && tmp - '-');
if (tmp == '-') {sgn = 0; tmp = getchar();}
do res = (res << 3) + (res << 1) + tmp - '0';
while (isdigit(tmp = getchar()));
return sgn ? res : -res;
}

int main()
{
freopen("form.in", "r", stdin);
freopen("form.out", "w", stdout);
n = getint(), m = getint();
for (int i = 1; i < n + 1; ++i)
{
*s[i] = s[i][1] = getint();
int pre = g.pred(*s[i]),
suc = g.succ(*s[i]);
ans = std::min(ans, suc - *s[i]);
ans = std::min(ans, *s[i] - pre);
g.Ins(*s[i]);
}
for (int i = 1; i < n; ++i)
S.Ins(abs(*s[i] - *s[i + 1]));
memset(Min, 0x3f, sizeof Min);
bool flag = 1;
for (int i, val, tmp; m; --m)
switch (scanf("%s", str), strlen(str))
{
case 6:
i = getint(), val = getint();
if (ans > 0)
{
int pre = g.pred(val), suc = g.succ(val);
if (val - pre < ans) ans = val - pre;
if (suc - val < ans) ans = suc - val;
g.Ins(val);
}
if (flag)
{
if (i < n) S.Del(abs(s[i][1] - *s[i + 1]));
if ((tmp = abs(s[i][1] - val)) < Min[i])
{
if (!tmp) {flag = 0; break;}
if (Min[i] < INF) S.Del(Min[i]);
S.Ins(Min[i] = tmp);
}
s[i][1] = val;
if (i < n) S.Ins(abs(val - *s[i + 1]));
}
break;
case 7: printf("%d\n", S.min()); break;
case 12: printf("%d\n", ans); break;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息