★【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;
}
相关文章推荐
- BZOJ 1058: [ZJOI2007]报表统计 STL
- BZOJ1058(ZJOI2007)报表统计--STL
- BZOJ_1058_[ZJOI2007]报表统计_STL
- bzoj1058: [ZJOI2007]报表统计 STL
- BZOJ 1058: [ZJOI2007]报表统计 STL 维护全局和局部最优值
- 【BZOJ1058】[ZJOI2007]报表统计 STL
- BZOJ1058 [ZJOI2007]报表统计 STL
- 【STL】报表统计
- 索骥馆-OFFICE系列之《北风网Excel高端应用培训:多条件约束报表自动统计系统分析与制作》共4章更新完
- Oracle通用行转列方法,适合报表统计等
- 虚心像报表统计分析高手请教,接近200个商品的零售统计分析功能
- 一个简单的多数据集取数的统计报表
- BZOJ 1058 报表统计
- 参会次数统计报表
- GDI/GDI+ 绘制网站流量统计报表 总结(5)
- 使用C#和Excel进行报表开发(二)-操作统计图(Chart)
- 报表统计
- VB.NET结合EXCEL统计生产报表
- 润乾报表统计图数据重叠处理方式
- 润乾集算报表非常规统计之固定分组