BZOJ 1500([NOI2005]维修数列-Splay的数列维护)

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 3087  Solved: 920
[Submit][Status][Discuss]

Description

Input

输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。 第2行包含N个数字,描述初始时的数列。 以下M行,每行一条命令,格式参见问题描述中的表格。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8

2 -6 3 5 1 -5 -3 6 3

GET-SUM 5 4

MAX-SUM

INSERT 8 3 -5 7 2

DELETE 12 1

MAKE-SAME 3 3 2

REVERSE 3 6

GET-SUM 5 4

MAX-SUM

Sample Output

-1

10

1

10

HINT

Splay解决数列维护。

推荐:用伸展树解决数列维护问题

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN (500000+10)
#define MAXM (20000+10)
#define INF (0xfffffff)
struct node
{
	int value,MaxL,MaxR,MaxM,sum,size;
	bool rev,same;
	node *ch[2],*pre;
	node(node *f,int _value,int _MaxL,int _MaxR,int _MaxM,int _sum,int _size):value(_value),MaxL(_MaxL),MaxR(_MaxR),MaxM(_MaxM),sum(_sum),size(_size){rev=same=0,pre=f,ch[0]=ch[1]=NULL;}
	node(){rev=same=0;}
	int l_siz(){if (ch[0]) return ch[0]->size;else return 0;}
//	int r_siz(){return (ch[1])?ch[1]->size:0;}

	friend void pushdown(node *x)
	{
		if (x)
		{
			if (x->rev)
			{
				x->rev=0;
				if (x->ch[0]) x->ch[0]->rev^=1;
				if (x->ch[1]) x->ch[1]->rev^=1;
				swap(x->ch[0],x->ch[1]);
				swap(x->MaxL,x->MaxR);
			}
			if (x->same)
			{
				x->same=0;
				if (x->ch[0]) {x->ch[0]->same=1;x->ch[0]->value=x->value;x->ch[0]->sum=x->value*x->ch[0]->size;x->ch[0]->MaxL=x->ch[0]->MaxR=x->ch[0]->MaxM=max(x->value,x->ch[0]->sum);}
				if (x->ch[1]) {x->ch[1]->same=1;x->ch[1]->value=x->value;x->ch[1]->sum=x->value*x->ch[1]->size;x->ch[1]->MaxL=x->ch[1]->MaxR=x->ch[1]->MaxM=max(x->value,x->ch[1]->sum);}
			}
		}
	}
	friend void update(node *x)
	{
		if (x)
		{
			pushdown(x->ch[0]);pushdown(x->ch[1]); //由于有坑爹的rev操作,必须先down.
			x->size=((x->ch[0])?x->ch[0]->size:0)+((x->ch[1])?x->ch[1]->size:0)+1;
			x->sum=((x->ch[0])?x->ch[0]->sum:0)+((x->ch[1])?x->ch[1]->sum:0)+x->value;
			x->MaxL=max(((x->ch[0])?x->ch[0]->MaxL:x->value),((x->ch[0])?x->ch[0]->sum:0)+x->value+max(0,((x->ch[1])?x->ch[1]->MaxL:0)));
			x->MaxR=max(((x->ch[1])?x->ch[1]->MaxR:x->value),((x->ch[1])?x->ch[1]->sum:0)+x->value+max(0,((x->ch[0])?x->ch[0]->MaxR:0)));
		//	cout<<((x->ch[1])?x->ch[1]->MaxR:x->value)<<' '<<+max(0,(((x->ch[0])?x->ch[0]->MaxR:0)))<<endl;
			x->MaxM=max(max(((x->ch[0])?x->ch[0]->MaxM:x->value),((x->ch[1])?x->ch[1]->MaxM:x->value)),((x->ch[0])?max(x->ch[0]->MaxR,0):0)+((x->ch[1])?max(x->ch[1]->MaxL,0):0)+x->value);
		}
	}
};
node *q[MAXN];
int q_siz=0;
int n,m,a[MAXN];
node* newnode(node *f,int value,int MaxL,int MaxR,int MaxM,int sum,int size)
{
	if (q_siz)
	{
		q[q_siz]->value=value;
		q[q_siz]->MaxL=MaxL;
		q[q_siz]->MaxR=MaxR;
		q[q_siz]->MaxM=MaxM;
		q[q_siz]->sum=sum;
		q[q_siz]->size=size;
		q[q_siz]->rev=q[q_siz]->same=0;q[q_siz]->pre=f;q[q_siz]->ch[0]=q[q_siz]->ch[1]=NULL;
		return q[q_siz--];
	}
	node *x=new node(f,value,MaxL,MaxR,MaxM,sum,size);
	return x;
}
node* newnode()
{
	if (q_siz) return q[q_siz--];
	node *x=new node();
	return x;
}
void addnode(node *x)
{
	q[++q_siz]=x;
	*x=node();
}
struct Splay
{
	node *root;
	Splay()
	{
		root=newnode(NULL,-INF,-INF,-INF,-INF,0,2);
		root->ch[0]=newnode(root,-INF,-INF,-INF,-INF,0,1);
	}
	void Print(node *x)
	{
		if (x->ch[0]) {cout<<"(",Print(x->ch[0]),cout<<")-";}
		cout<<x->same;
		if (x->ch[1]) cout<<"-(",Print(x->ch[1]),cout<<")";
	}
	void rotate(node *x,int c) //0左旋 1右旋
	{
		node *y=x->pre;
		pushdown(y),pushdown(x);
		y->ch[!c]=x->ch[c];
		if (x->ch[c]!=NULL) x->ch[c]->pre=y;
		x->pre=y->pre;
		if (y->pre!=NULL)
		{
			if (y->pre->ch[0]==y) y->pre->ch[0]=x;
			else y->pre->ch[1]=x;
		}
		x->ch[c]=y;y->pre=x;
		if (y==root) root=x;
		update(y);
	}
	void splay(node *x,node *f)
	{
		for(pushdown(x);x->pre!=f;)
		{
			if (x->pre->pre==f)
			{
				if (x->pre->ch[0]==x) rotate(x,1);
				else rotate(x,0);
			}
			else
			{
				node *y=x->pre,*z=y->pre;
				pushdown(z);pushdown(y);pushdown(x); //rev改变树结构
				if (y->ch[0]==x&&z->ch[0]==y) rotate(y,1),rotate(x,1);
				else if (y->ch[1]==x&&z->ch[1]==y) rotate(y,0),rotate(x,0);
				else if (y->ch[0]==x&&z->ch[1]==y) rotate(x,1),rotate(x,0);
				else if (y->ch[1]==x&&z->ch[0]==y) rotate(x,0),rotate(x,1);
			}
			update(x);
			//Print(root);cout<<endl;
		}
	}
	node* find_kth(node *x,int k)
	{
		pushdown(x); //确保x正确
		if (x->l_siz()>=k) return find_kth(x->ch[0],k);
		if (x->l_siz()+1==k) return x;
		else return find_kth(x->ch[1],k-x->l_siz()-1);
	}
	void build(node *f,node *x,int l,int r)
	{
		if (l>r) return;
		int m=(l+r)>>1;
		*x=node(f,a[m],a[l],a[r],a[m],a[m],1);
		if (l<m) build(x,x->ch[0]=newnode(),l,m-1);
		if (m<r) build(x,x->ch[1]=newnode(),m+1,r);
		if (l<r) update(x);
	}
	void del(node *x)
	{
		if (x->ch[0]) del(x->ch[0]);
		if (x->ch[1]) del(x->ch[1]);
		addnode(x);
	}
	void insert(int pos,int tot)
	{
		splay(find_kth(root,pos+1),NULL);
		splay(find_kth(root,pos+2),root);
		root->ch[1]->ch[0]=newnode();
		build(root->ch[1],root->ch[1]->ch[0],1,tot);
		update(root->ch[1]);update(root);
	}
	void delet(int pos,int tot)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		//Print(root);
		del(root->ch[1]->ch[0]);
		root->ch[1]->ch[0]=NULL;
		update(root->ch[1]);update(root);
	}
	void reverse(int pos,int tot)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		root->ch[1]->ch[0]->rev^=1;
		update(root->ch[1]);update(root);
	}
	void make_same(int pos,int tot,int c)
	{
		splay(find_kth(root,pos),NULL);
		splay(find_kth(root,pos+1+tot),root);
		node *x=root->ch[1]->ch[0];
		x->same=1;
		x->value=c;
		x->sum=c*x->size;
		x->MaxL=x->MaxR=x->MaxM=max(x->value,x->sum);
		update(root->ch[1]);update(root);
	}
	void get_sum(int pos,int tot)
	{
		if (tot==0)
		{
			printf("0n");
			return;
		}
		splay(find_kth(root,pos),NULL);
		//Print(root);cout<<endl;
		splay(find_kth(root,pos+1+tot),root);
		//Print(root);cout<<endl;
		node *x=root->ch[1]->ch[0];
		printf("%dn",x->sum);
	}
	void max_sum()
	{
		splay(find_kth(root,1),NULL);
		splay(find_kth(root,root->size),root);
		printf("%dn",root->ch[1]->ch[0]->MaxM);
	}
}S;
int main()
{
//	freopen("bzoj1500.in","r",stdin);
	cin>>n>>m;
	for (int i=1;i<=n;i++) cin>>a[i];
	S.insert(0,n);
	//S.Print(S.root);cout<<endl;
	for (int i=1;i<=m;i++)
	{
	//	cout<<i<<':';
		char s[10];
		scanf("%s",s);
		switch (s[2])
		{
			case'S':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					for (int i=1;i<=tot;i++) scanf("%d",&a[i]);
					S.insert(pos,tot);
					break;
				}
			case'L':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.delet(pos,tot);
					break;
				}
			case'K':
				{
					int pos,tot,c;
					scanf("%d%d%d",&pos,&tot,&c);
					S.make_same(pos,tot,c);
					break;
				}
			case'V':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.reverse(pos,tot);
					break;
				}
			case'T':
				{
					int pos,tot;
					scanf("%d%d",&pos,&tot);
					S.get_sum(pos,tot);
					break;
				}
			case'X':
				{
					S.max_sum();
					break;
				}
		}
		//S.Print(S.root);cout<<endl;
	}
	return 0;
}

BZOJ 1034([ZJOI2008]泡泡堂BNB-田忌赛马)

1034: [ZJOI2008]泡泡堂BNB

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 682  Solved: 321
[Submit][Status][Discuss]

Description

 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂。每一场比赛前,对阵双方的教练向组委会提交一份参赛选手的名单,决定了选手上场的顺序,一经确定,不得修改。比赛中,双方的一号选手,二号选手……,n号选手捉对厮杀,共进行n场比赛。每胜一场比赛得2分,平一场得1分,输一场不得分。最终将双方的单场得分相加得出总分,总分高的队伍晋级(总分相同抽签决定)。
作为浙江队的领队,你已经在事先将各省所有选手的泡泡堂水平了解的一清二楚,并将其用一个实力值来衡量。为简化问题,我们假定选手在游戏中完全不受任何外界因素干扰,即实力强的选手一定可以战胜实力弱的选手,而两个实力相同的选手一定会战平。由于完全不知道对手会使用何种策略来确定出场顺序,所以所有的队伍都采取了这样一种策略,就是完全随机决定出场顺序。 当然你不想这样不明不白的进行比赛。你想事先了解一下在最好与最坏的情况下,浙江队最终分别能得到多少分。

Input

输入的第一行为一个整数n,表示每支代表队的人数。 接下来n行,每行一个整数,描述了n位浙江队的选手的实力值。 接下来n行,每行一个整数,描述了你的对手的n位选手的实力值。 20%的数据中,1<=n<=10; 40%的数据中,1<=n<=100; 60%的数据中,1<=n<=1000; 100%的数据中,1<=n<=100000,且所有选手的实力值在0到10000000之间。

Output

包括两个用空格隔开的整数,分别表示浙江队在最好与最坏的情况下分别能得多少分。不要在行末输出多余的空白字符。

Sample Input

2

1

3

2

4

Sample Output

2 0

样例说明

我们分别称4位选手为A,B,C,D。则可能出现以下4种对战方式,最好情况下可得2分,最坏情况下得0分。

一 二 三 四

浙江 ??? 结果 浙江 ??? 结果 浙江 ??? 结果 浙江 ??? 结果

一号选手 A C 负 A D 负 B C 胜 B D 负

二号选手 B D 负 B C 胜 A D 负 A C 负

总得分 0 2 2 0



田忌赛马加强版。

尽可能让最弱的赢,最强的赢,都不行则最弱打最强

错误的贪心:

让最弱的能赢/平则赢/平,否则让其与最强的打

反例:

2

1 2 6 7

1 2 4 7

 ans1=6

反例ans1=5


最差情况:

容易发现2个队伍的总分一定(2-0,1-1,0-2)

 所以ans2=2n-B队最高分

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN (100000+10)
int n,a[MAXN],b[MAXN];
int calc()
{
	int i=1,j=1,k=n,l=n,ans=0;
	while (i<=k)
	{
		if (a[i]>b[j]) ans+=2,i++,j++;
		else if(a[k]>b[l]) ans+=2,k--,l--;
		else ans+=(a[i]==b[l]),i++,l--;
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<=n;i++) scanf("%d",&b[i]);
	sort(a+1,a+1+n);sort(b+1,b+1+n);
	cout<<calc()<<' ';
	swap(a,b);
	cout<<2*n-calc()<<endl;
	return 0;
}

STL list链表的用法详解

转载自:http://www.cnblogs.com/this-543273659/archive/2011/08/01/2123373.html

本文以List容器为例子,介绍了STL的基本内容,从容器到迭代器,再到普通函数,而且例子丰富,通俗易懂。不失为STL的入门文章,新手不容错过!

 

  0 前言

  1 定义一个list

  2 使用list的成员函数push_back和push_front插入一个元素到list中

  3 list的成员函数empty()

  4 用for循环来处理list中的元素

  5 用STL的通用算法for_each来处理list中的元素

  6 用STL的通用算法count_if()来统计list中的元素个数

  7 使用count_if()的一个更加复杂的函数对象。

  8 使用STL通用算法find()在list中查找对象

  9 使用STL通用算法find_if()在list中搜索对象

  10 使用STL通用算法search在list中找一个序列

  11 使用list的成员函数sort()排序一个list。

  12 用list的成员函数插入元素到list中

  13 List 构造函数

  14 使用list成员函数从list中删除元素

  15 用list成员函数remove()从list中删除元素。

  16 使用STL通用算法remove()从list中删除元素

  17 使用STL通用算法stable_partition()和list成员函数splice()来划分一个list

  18 结论

  在field中使用STL

  19 参考书目

 

 

0 前言

 

    这篇文章是关于C++语言的一个新的扩展——标准模板库的(Standard Template Library),也叫STL。

 

    当我第一次打算写一篇关于STL的文章的时候,我不得不承认我当时低估了这个话题的深度和广度。有很多内容要含盖,也有很多详细描述STL的书。因此我重新考虑了一下我原来的想法。我为什么要写这篇文章,又为什么要投稿呢?这会有什麽用呢?有再来一篇关于STL的文章的必要吗?

    当我翻开Musser and Saini的页时,我看到了编程时代在我面前消融。我能看到深夜消失了,目标软件工程出现了。我看到了可维护的代码。一年过去了,我使用STL写的软件仍然很容易维护。让人吃惊的是其他人可以没有我而维护的很好!

    然而,我也记得在一开始的时候很难弄懂那些技术术语。一次,我买了Musser&Saini,每件事都依次出现,但是在那以前我最渴望得到的东西是一些好的例子。

    当我开始的时候,作为C++一部分的Stroustrup还没出来,它覆盖了STL。

    因此我想写一篇关于一个STL程序员的真实生活的文章可能会有用。如果我手上有一些好的例子的话,特别是象这样的新题目,我会学的更快。

    另外一件事是STL应该很好用。因此,理论上说,我们应该可以马上开始使用STL。

    什麽是STL呢?STL就是Standard Template Library,标准模板库。这可能是一个历史上最令人兴奋的工具的最无聊的术语。从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。

    STL的目的是标准化组件,这样你就不用重新开发它们了。你可以仅仅使用这些现成的组件。STL现在是C++的一部分,因此不用额外安装什麽。它被内建在你的编译器之内。因为STL的list是一个简单的容器,所以我打算从它开始介绍STL如何使用。如果你懂得了这个概念,其他的就都没有问题了。另外,list容器是相当简单的,我们会看到这一点。

    这篇文章中我们将会看到如何定义和初始化一个list,计算它的元素的数量,从一个list里查找元素,删除元素,和一些其他的操作。要作到这些,我们将会讨论两个不同的算法,STL通用算法都是可以操作不止一个容器的,而list的成员函数是list容器专有的操作。

    这是三类主要的STL组件的简明纲要。STL容器可以保存对象,内建对象和类对象。它们会安全的保存对象,并定义我们能够操作的这个对象的接口。放在蛋架上的鸡蛋不会滚到桌上。它们很安全。因此,在STL容器中的对象也很安全。我知道这个比喻听起来很老土,但是它很正确。

    STL算法是标准算法,我们可以把它们应用在那些容器中的对象上。这些算法都有很著名的执行特性。它们可以给对象排序,删除它们,给它们记数,比较,找出特殊的对象,把它们合并到另一个容器中,以及执行其他有用的操作。

    STL iterator就象是容器中指向对象的指针。STL的算法使用iterator在容器上进行操作。Iterator设置算法的边界,容器的长度,和其他一些事情。举个例子,有些iterator仅让算法读元素,有一些让算法写元素,有一些则两者都行。 Iterator也决定在容器中处理的方向。

    你可以通过调用容器的成员函数begin()来得到一个指向一个容器起始位置的iterator。你可以调用一个容器的 end() 函数来得到过去的最后一个值(就是处理停在那的那个值)。

    这就是STL所有的东西,容器、算法、和允许算法工作在容器中的元素上的iterator。算法以合适、标准的方法操作对象,并可通过iterator得到容器精确的长度。一旦做了这些,它们就在也不会“跑出边界”。还有一些其他的对这些核心组件类型有功能性增强的组件,例如函数对象。我们将会看到有关这些的例子,现在 ,我们先来看一看STL的list。

 

 

--------------------------------------------------------------------------------

 

1 定义一个list

 

我们可以象这样来定义一个STL的list:

#include <string>

#include <list>

int main (void)

{

list<string> Milkshakes;

return 0;

}

这就行了,你已经定义了一个list。简单吗?list<string> Milkshakes这句是你声明了list<string>模板类的一个实例,然后就是实例化这个类的一个对象。但是我们别急着做这个。在这一步其实你只需要知道你定义了 一个字符串的list。你需要包含提供STL list类的头文件。我用gcc 2.7.2在我的Linux上编译这个测试程序,例如:

 

g++ test1.cpp -o test1

 

注意iostream.h这个头文件已经被STL的头文件放弃了。这就是为什么这个例子中没有它的原因。

 

现在我们有了一个list,我们可以看实使用它来装东西了。我们将把一个字符串加到这个list里。有一个非常 重要的东西叫做list的值类型。值类型就是list中的对象的类型。在这个例子中,这个list的值类型就是字符串,string , 这是因为这个list用来放字符串。

 

 

--------------------------------------------------------------------------------

 

2 使用list的成员函数push_back和push_front插入一个元素到list中

 

#include <string>

#include <list>

 

int main (void)

{

list<string> Milkshakes;

Milkshakes.push_back("Chocolate");

Milkshakes.push_back("Strawberry");

Milkshakes.push_front("Lime");

Milkshakes.push_front("Vanilla");

return 0;

}

我们现在有个4个字符串在list中。list的成员函数push_back()把一个对象放到一个list的后面,而 push_front()把对象放到前面。我通常把一些错误信息push_back()到一个list中去,然后push_front()一个标题到list中, 这样它就会在这个错误消息以前打印它了。

 

 

--------------------------------------------------------------------------------

 

3 list的成员函数empty()

 

知道一个list是否为空很重要。如果list为空,empty()这个成员函数返回真。 我通常会这样使用它。通篇程序我都用push_back()来把错误消息放到list中去。然后,通过调用empty() 我就可以说出这个程序是否报告了错误。如果我定义了一个list来放信息,一个放警告,一个放严重错误, 我就可以通过使用empty()轻易的说出到底有那种类型的错误发生了。

我可以整理这些list,然后在打印它们之前,用标题来整理它们,或者把它们排序成类。

 

/*

|| Using a list to track and report program messages and status

*/

#include <iostream.h>

#include <string>

#include <list>

int main (void)

{

    #define OK 0

    #define INFO 1

    #define WARNING 2

    int return_code;

    list<string> InfoMessages;

    list<string> WarningMessages;

 

    // during a program these messages are loaded at various points

    InfoMessages.push_back("Info: Program started");

    // do work...

    WarningMessages.push_back("Warning: No Customer records have been found");

    // do work...

 

  return_code = OK;

 

    if  (!InfoMessages.empty()) {          // there were info messages

       InfoMessages.push_front("Informational Messages:");

       // ... print the info messages list, we'll see how later

       return_code = INFO;

    }

 

    if  (!WarningMessages.empty()) {       // there were warning messages

       WarningMessages.push_front("Warning Messages:");

       // ... print the warning messages list, we'll see how later

       return_code = WARNING;

    }

 

    // If there were no messages say so.

    if (InfoMessages.empty() && WarningMessages.empty()) {

       cout << "There were no messages " << endl;

    }

 

    return return_code;

}

 

 

--------------------------------------------------------------------------------

 

4 用for循环来处理list中的元素

 

我们想要遍历一个list,比如打印一个中的所有对象来看看list上不同操作的结果。要一个元素一个元素的遍历一个list, 我们可以这样做:

 

/*

|| How to print the contents of a simple STL list. Whew!

*/

#include <iostream.h>

#include <string>

#include <list>

 

int main (void)

{

    list<string> Milkshakes;

    list<string>::iterator MilkshakeIterator;

 

    Milkshakes.push_back("Chocolate");

    Milkshakes.push_back("Strawberry");

    Milkshakes.push_front("Lime");

    Milkshakes.push_front("Vanilla");

 

    // print the milkshakes

    Milkshakes.push_front("The Milkshake Menu");

    Milkshakes.push_back("*** Thats the end ***");

    for (MilkshakeIterator=Milkshakes.begin();

           MilkshakeIterator!=Milkshakes.end();

            ++MilkshakeIterator)

    {

      // dereference the iterator to get the element

      cout << *MilkshakeIterator << endl;

    }

}

这个程序定义了一个iterator,MilkshakeIterator。我们把它指向了这个list的第一个元素。 这可以调用Milkshakes.begin()来作到,它会返回一个指向list开头的iterator。然后我们把它和Milkshakes.end()的 返回值来做比较,当我们到了那儿的时候就停下来。

 

容器的end()函数会返回一个指向容器的最后一个位置的iterator。当我们到了那里,就停止操作。 我们不能不理容器的end()函数的返回值。我们仅知道它意味着已经处理到了这个容器的末尾,应该停止处理了。 所有的STL容器都要这样做。

 

在上面的例子中,每一次执行for循环,我们就重复引用iterator来得到我们打印的字符串。

 

在STL编程中,我们在每个算法中都使用一个或多个iterator。我们使用它们来存取容器中的对象。 要存取一个给定的对象,我们把一个iterator指向它,然后间接引用这个iterator。

 

这个list容器,就象你所想的,它不支持在iterator加一个数来指向隔一个的对象。 就是说,我们不能用Milkshakes.begin()+2来指向list中的第三个对象,因为STL的list是以双链的list来实现的, 它不支持随机存取。vector和deque(向量和双端队列)和一些其他的STL的容器可以支持随机存取。

 

上面的程序打印出了list中的内容。任何人读了它都能马上明白它是怎麽工作的。它使用标准的iterator和标准 的list容器。没有多少程序员依赖它里面装的东西, 仅仅是标准的C++。这是一个向前的重要步骤。这个例子使用STL使我们的软件更加标准。

 

 

--------------------------------------------------------------------------------

 

5 用STL的通用算法for_each来处理list中的元素

 

使用STL list和 iterator,我们要初始化、比较和给iterator增量来遍历这个容器。STL通用的for_each 算法能够减轻我们的工作。

/*

|| How to print a simple STL list MkII

*/

#include <iostream.h>

#include <string>

#include <list>

#include <algorithm>

 

PrintIt (string& StringToPrint)

{

    cout << StringToPrint << endl;

}

 

int main (void)

{

    list<string> FruitAndVegetables;

    FruitAndVegetables.push_back("carrot");

    FruitAndVegetables.push_back("pumpkin");

    FruitAndVegetables.push_back("potato");

    FruitAndVegetables.push_front("apple");

    FruitAndVegetables.push_front("pineapple");

 

    for_each  (FruitAndVegetables.begin(), FruitAndVegetables.end(), PrintIt);

}

在这个程序中我们使用STL的通用算法for_each()来遍历一个iterator的范围,然后调用PrintIt()来处理每个对象。 我们不需要初始化、比较和给iterator增量。for_each()为我们漂亮的完成了这些工作。我们执行于对象上的 操作被很好的打包在这个函数以外了,我们不用再做那样的循环了,我们的代码更加清晰了。

for_each算法引用了iterator范围的概念,这是一个由起始iterator和一个末尾iterator指出的范围。 起始iterator指出操作由哪里开始,末尾iterator指明到哪结束,但是它不包括在这个范围内。用STL的通用算法count()来统计list中的元素个数。

 

 

--------------------------------------------------------------------------------

 

5.2用STL的通用算法count()来统计list中的元素个数

 

STL的通用算法count()和count_if()用来给容器中的对象记数。就象for_each()一样,count()和count_if() 算法也是在iterator范围内来做的。

 

让我们在一个学生测验成绩的list中来数一数满分的个数。这是一个整型的List。

 

/*

|| How to count objects in an STL list

*/

#include <list>

#include <algorithm>

int main (void)

{

    list<int> Scores;

    Scores.push_back(100);

    Scores.push_back(80);

    Scores.push_back(45);

    Scores.push_back(75);

    Scores.push_back(99);

    Scores.push_back(100);

 

    int NumberOf100Scores(0);

    //count (Scores.begin(), Scores.end(), 100, NumberOf100Scores);

    NumberOf100Scores = count(Scores.begin(), Scores.end(), 100);

    cout << "There were " << NumberOf100Scores << " scores of 100" << endl;

}

 

count()算法统计等于某个值的对象的个数。上面的例子它检查list中的每个整型对象是不是100。每次容器中的对象等于100,它就给NumberOf100Scores加1。这是程序的输出:

程序的输出:

There were 2 scores of 100

 

 

--------------------------------------------------------------------------------

 

6.用STL的通用算法count_if()来统计list中的元素个数

 

    count_if()是count()的一个更有趣的版本。他采用了STL的一个新组件,函数对象。count_if() 带一个函数对象的参数。函数对象是一个至少带有一个operator()方法的类。有些STL算法作为参数接收函数对象并调用这个函数对象的operator()方法。

    函数对象被约定为STL算法调用operator时返回true或false。它们根据这个来判定这个函数。举个例子会说的更清楚些。

    count_if()通过传递一个函数对象来作出比count()更加复杂的评估以确定一个对象是否应该被记数。

 

    在这个例子里我们将数一数牙刷的销售数量。我们将提交包含四个字符的销售码和产品说明的销售记录。

 

/* || Using a function object to help count things */

#include <string>

#include <list>

#include <algorithm>

 

const string ToothbrushCode("0003");

 

class IsAToothbrush

{

public:

    bool operator() ( string& SalesRecord )

    {

        return SalesRecord.substr(0,4)==ToothbrushCode;

    }

};

 

int main (void)

{

    list<string> SalesRecords;

    SalesRecords.push_back("0001 Soap");

    SalesRecords.push_back("0002 Shampoo");

    SalesRecords.push_back("0003 Toothbrush");

    SalesRecords.push_back("0004 Toothpaste");

    SalesRecords.push_back("0003 Toothbrush");

    int NumberOfToothbrushes(0);

    count_if (SalesRecords.begin(), SalesRecords.end(), IsAToothbrush(), NumberOfToothbrushes);

    cout << "There were " << NumberOfToothbrushes << " toothbrushes sold" << endl;

}

 

这是这个程序的输出:

There were 2 toothbrushes sold

 

这个程序是这样工作的:定义一个函数对象类IsAToothbrush,这个类的对象能判断出卖出的是否是牙刷 。如果这个记录是卖出牙刷的记录的话,函数调用operator()返回一个true,否则返回false。

 

count_if()算法由第一和第二两个iterator参数指出的范围来处理容器对象。它将对每个 IsAToothbrush()返回true的容器中的对象增加NumberOfToothbrushes的值。

 

最后的结果是NumberOfToothbrushes这个变量保存了产品代码域为"0003"的记录的个数,也就是牙刷的个数。

 

注意count_if()的第三个参数IsAToothbrush(),它是由它的构造函数临时构造的一个对象。你可以把IsAToothbrush类的一个临时对象 传递给count_if()函数。count_if()将对该容器的每个对象调用这个函数。

 

 

--------------------------------------------------------------------------------

 

7 使用count_if()的一个更加复杂的函数对象。

 

使用count_if()的一个更加复杂的函数对象。

    我们可以更进一步的研究一下函数对象。假设我们需要传递更多的信息给一个函数对象。我们不能通过调用operator来作到这点,因为必须定义为一个list的中的对象的类型。 然而我们通过为IsAToothbrush指出一个非缺省的构造函数就可以用任何我们所需要的信息来初始化它了。 例如,我们可能需要每个牙刷有一个不定的代码。我们可以把这个信息加到下面的函数对象中:

 

/*

|| Using a more complex function object

*/

#include <iostream.h>

#include <string>

#include <list>

#include <algorithm>

 

class IsAToothbrush

{

public:

    IsAToothbrush(string& InToothbrushCode) : ToothbrushCode(InToothbrushCode) {}

    bool operator() (string& SalesRecord)

    {

        return SalesRecord.substr(0,4)==ToothbrushCode;

    }

private:

    string ToothbrushCode;

};

 

int main (void)

{

    list<string> SalesRecords;

 

    SalesRecords.push_back("0001 Soap");

    SalesRecords.push_back("0002 Shampoo");

    SalesRecords.push_back("0003 Toothbrush");

    SalesRecords.push_back("0004 Toothpaste");

    SalesRecords.push_back("0003 Toothbrush");

 

    string VariableToothbrushCode("0003");

 

    int NumberOfToothbrushes(0);

    count_if (SalesRecords.begin(), SalesRecords.end(), IsAToothbrush(VariableToothbrushCode), NumberOfToothbrushes);

    cout << "There were  "

         << NumberOfToothbrushes

         << " toothbrushes matching code "

         << VariableToothbrushCode

         << " sold"

         << endl;

}

 

程序的输出是:

There were 2 toothbrushes matching code 0003 sold

 

这个例子演示了如何向函数对象传递信息。你可以定义任意你想要的构造函数,你可以再函数对象中做任何你 想做的处理,都可以合法编译通过。

 

你可以看到函数对象真的扩展了基本记数算法。

 

到现在为止,我们都学习了:

 

定义一个list

向list中加入元素

如何知道list是否为空

如何使用for循环来遍历一个list

如何使用STL的通用算法for_each来遍历list

list成员函数begin() 和 end() 以及它们的意义

iterator范围的概念和一个范围的最后一个位置实际上并不被处理这一事实

如何使用STL通用算法count()和count_if()来对一个list中的对象记数

如何定义一个函数对象

我选用这些例子来演示list的一般操作。如果你懂了这些基本原理,你就可以毫无疑问的使用STL了 建议你作一些练习。我们现在用一些更加复杂的操作来扩展我们的知识,包括list成员函数和STL通用算法。

 

输出是:

Pineapple

 

如果没有找到指出的对象,就会返回Fruit.end()的值,要是找到了就返回一个指着找到的对象的iterator

 

 

--------------------------------------------------------------------------------

 

8.使用STL通用算法find()在list中查找对象

 

我们如何在list中查找东西呢?

STL的通用算法find()和find_if()可以做这些。

就象for_each(), count(), count_if() 一样,这些算法也使用iterator范围,这个范围指出一个list或任意其他容器中的一部分来处理。通常首iterator指着开始的位置,次iterator指着停止处理的地方。由次iterator指出的元素不被处理。

这是find()如何工作:

/*

|| How to find things in an STL list

*/

#include <string>

#include <list>

#include <algorithm>

 

int main (void)

{

    list<string> Fruit;

    list<string>::iterator FruitIterator;

 

    Fruit.push_back("Apple");

    Fruit.push_back("Pineapple");

    Fruit.push_back("Star Apple");

 

    FruitIterator = find (Fruit.begin(), Fruit.end(), "Pineapple");

 

    if (FruitIterator == Fruit.end())

    {

        cout << "Fruit not found in list" << endl;

    }

    else

    {

        cout << *FruitIterator << endl;

    }

}

 

输出是:

Pineapple

如果没有找到指出的对象,就会返回Fruit.end()的值,要是找到了就返回一个指着找到的对象i

 

 

--------------------------------------------------------------------------------

 

9.使用STL通用算法find_if()在list中搜索对象

 

    这是find()的一个更强大的版本。这个例子演示了find_if(),它接收一个函数对象的参数作为参数,并使用它来做更复杂的评价对象是否和给出的查找条件相付。

    假设我们的list中有一些按年代排列的包含了事件和日期的记录。我们希望找出发生在1997年的事件。

 

这是find()的一个更强大的版本。这个例子演示了find_if(),它接收一个函数对象的参数作为参数, 并使用它来做更复杂的评价对象是否和给出的查找条件相付。假设我们的list中有一些按年代排列的包含了事件和日期的记录。我们希望找出发生在1997年的事件。

/*

|| How to find things in an STL list MkII

*/

#include <string>

#include <list>

#include <algorithm>

 

class EventIsIn1997

{

public:

    bool operator () (string& EventRecord)

    {

        // year field is at position 12 for 4 characters in EventRecord

        return EventRecord.substr(12,4)=="1997";

    }

};

 

int main (void)

{

    list<string> Events;

 

    // string positions 0123456789012345678901234567890123456789012345

    Events.push_back("07 January 1995 Draft plan of house prepared");

    Events.push_back("07 February 1996 Detailed plan of house prepared");

    Events.push_back("10 January 1997 Client agrees to job");

    Events.push_back("15 January 1997 Builder starts work on bedroom");

    Events.push_back("30 April 1997 Builder finishes work");

 

    list<string>::iterator EventIterator = find_if (Events.begin(), Events.end(), EventIsIn1997());

 

    // find_if completes the first time EventIsIn1997()() returns true

    // for any object. It returns an iterator to that object which we

    // can dereference to get the object, or if EventIsIn1997()() never

    // returned true, find_if returns end()

    if (EventIterator==Events.end())

    {

        cout << "Event not found in list" << endl;

    }

    else

    {

        cout << *EventIterator << endl;

    }

}

这是程序的输出:

10 January 1997 Client agrees to job

 

 

--------------------------------------------------------------------------------

 

10.使用STL通用算法search在list中找一个序列

 

一些字符在STL容器中很好处理,让我们看一看一个难处理的字符序列。我们将定义一个list来放字符。

list<char> Characters;

 

现在我们有了一个字符序列,它不用任何帮助就知道然后管理内存。它知道它是从哪里开始、到哪里结束。 它非常有用。我不知道我是否说过以null结尾的字符数组。

 

让我们加入一些我们喜欢的字符到这个list中:

 

Characters.push_back('');

Characters.push_back('');

Characters.push_back('1');

Characters.push_back('2');

我们将得到多少个空字符呢?

int NumberOfNullCharacters(0);

count(Characters.begin(), Characters.end(), '', NumberOfNullCharacters);

cout << "We have " << NumberOfNullCharacters << endl;

让我们找字符'1'

list<char>::iterator Iter;

Iter = find(Characters.begin(), Characters.end(), '1');

cout << "We found " << *Iter << endl;

这个例子演示了STL容器允许你以更标准的方法来处理空字符。现在让我们用STL的search算法来搜索容器中 的两个null。就象你猜的一样,STL通用算法search()用来搜索一个容器,但是是搜索一个元素串,不象find()和find_if() 只搜索单个的元素。

/*

|| How to use the search algorithm in an STL list

*/

#include <string>

#include <list>

#include <algorithm>

 

int main ( void)

{

    list<char> TargetCharacters;

    list<char> ListOfCharacters;

 

    TargetCharacters.push_back('');

    TargetCharacters.push_back('');

 

    ListOfCharacters.push_back('1');

    ListOfCharacters.push_back('2');

    ListOfCharacters.push_back('');

    ListOfCharacters.push_back('');

 

    list<char>::iterator PositionOfNulls = search(ListOfCharacters.begin(), ListOfCharacters.end(), TargetCharacters.begin(), TargetCharacters.end());

 

    if (PositionOfNulls!=ListOfCharacters.end())

        cout << "We found the nulls" << endl;

}

The output of the program will be 这是程序的输出:

We found the nulls

 

search算法在一个序列中找另一个序列的第一次出现的位置。在这个例子里我们在ListOfCharacters中 找TargetCharacters这个序列的第一次出现,TargetCharacters是包含两个null字符的序列。 search的参数是两个指着查找目标的iterator和两个指着搜索范围的iterators。 因此我们我们在整个的ListOfCharacters的范围内查找TargetCharacters这个list的整个序列。

 

如果TargetCharacters被发现,search就会返回一个指着ListOfCharacters中序列匹配的第一个 字符的iterator。如果没有找到匹配项,search返回ListOfCharacters.end()的值。

 

 

--------------------------------------------------------------------------------

 

11 使用list的成员函数sort()排序一个list。

 

    要排序一个list,我们要用list的成员函数sort(),而不是通用算法sort()。所有我们用过的算法都是通用算法。然而,在STL中有时容器支持它自己对一个特殊算法的实现,这通常是为了提高性能。

    在这个例子中,list容器有它自己的sort算法,这是因为通用算法仅能为那些提供随机存取里面元素的容器排序,而由于list是作为一个连接的链表实现的,它不支持对它里面的元素随机存取。所以就需要一个特殊的 sort()成员函数来排序list。

    由于各种原因,容器在性能需要较高或有特殊效果需求的场合支持外部函数(extra functions), 这通过利用构造函数的结构特性可以作到。

 

/* || How to sort an STL list */

#include <string>

#include <list>

#include <algorithm>

PrintIt (string& StringToPrint)

{

cout << StringToPrint << endl;

}

 

int main (void)

{

    list<string> Staff;

    list<string>::iterator PeopleIterator;

    Staff.push_back("John");

    Staff.push_back("Bill");

    Staff.push_back("Tony");

    Staff.push_back("Fidel");

    Staff.push_back("Nelson");

    cout << "The unsorted list " << endl;

    for_each(Staff.begin(), Staff.end(), PrintIt );

    Staff.sort();

    cout << "The sorted list " << endl;

    for_each(Staff.begin(), Staff.end(), PrintIt);

}

 

输出是:

The unsorted list  John Bill Tony Fidel Nelson The sorted list  Bill Fidel John Nelson Tony

 

 

--------------------------------------------------------------------------------

 

12.用list的成员函数插入元素到list中

 

    list的成员函数push_front()和push_back()分别把元素加入到list的前面和后面。你可以使用insert() 把对象插入到list中的任何地方。

    insert()可以加入一个对象,一个对象的若干份拷贝,或者一个范围以内的对象。这里是一些插入对象到list中的例子:

 

/*

|| Using insert to insert elements into a list.

*/

#include <list>

 

int main (void)

{

    list<int> list1;

 

    /*

    || Put integers 0 to 9 in the list

    */

    for (int i = 0; i < 10; ++i) list1.push_back(i);

 

    /*

    || Insert -1 using the insert member function

    || Our list will contain -1,0,1,2,3,4,5,6,7,8,9

    */

    list1.insert(list1.begin(), -1);

 

    /*

    || Insert an element at the end using insert

    || Our list will contain -1,0,1,2,3,4,5,6,7,8,9,10

    */

    list1.insert(list1.end(), 10);

 

    /*

    || Inserting a range from another container

    || Our list will contain -1,0,1,2,3,4,5,6,7,8,9,10,11,12

    */

    int IntArray[2] = {11,12};

    list1.insert(list1.end(), &IntArray[0], &IntArray[2]);

 

    /*

    || As an exercise put the code in here to print the lists!

    || Hint: use PrintIt and accept an interger

    */

}

注意,insert()函数把一个或若干个元素插入到你指出的iterator的位置。你的元素将出现在 iterator指出的位置以前。

 

 

--------------------------------------------------------------------------------

 

13.List 构造函数

 

我们已经象这样定义了list:

list<int> Fred;

 

你也可以象这样定义一个list,并同时初始化它的元素:

 

// define a list of 10 elements and initialise them all to 0

list<int> Fred(10, 0);

// list now contains 0,0,0,0,0,0,0,0,0,0

或者你可以定义一个list并用另一个STL容器的一个范围来初始化它,这个STL容器不一定是一个list, 仅仅需要是元素类型相同的的容器就可以。

vector<int> Harry;

Harry.push_back(1);

Harry.push_back(2);

#

// define a list and initialise it with the elements in Harry

list<int> Bill(Harry.begin(), Harry.end());

// Bill now contains 1,2

 

 

--------------------------------------------------------------------------------

 

14.使用list成员函数从list中删除元素

 

    list成员函数pop_front()删掉list中的第一个元素,pop_back()删掉最后一个元素。函数erase()删掉由一个iterator指出的元素。还有另一个erase()函数可以删掉一个范围的元素。

 

/* || Erasing objects from a list */

#include <list>

int main (void)

{

    list<int> list1;    // define a list of integers

 

    /* || Put some numbers in the list || It now contains 0,1,2,3,4,5,6,7,8,9 */

    for (int i = 0; i < 10; ++i)

        list1.push_back(i);

 

list1.pop_front();    // erase the first element 0

 

    list1.pop_back();     // erase the last element 9

 

    list1.erase(list1.begin());

    // erase the first element (1) using an iterator

 

    list1.erase(list1.begin(), list1.end());

    // erase all the remaining elements

 

    cout << "list contains " << list1.size() << " elements" << endl;

}

 

输出是:

list contains 0 elements

 

 

--------------------------------------------------------------------------------

 

15.用list成员函数remove()从list中删除元素。

 

/* || Using the list member function remove to remove elements */

#include <string>

#include <list>

#include <algorithm>

PrintIt (const string& StringToPrint)

{

cout << StringToPrint << endl;

}

 

int main (void)

{

list<string> Birds;

Birds.push_back("cockatoo");

Birds.push_back("galah");

Birds.push_back("cockatoo");

Birds.push_back("rosella");

Birds.push_back("corella");

cout << "Original list with cockatoos" << endl;

for_each(Birds.begin(), Birds.end(), PrintIt);

Birds.remove("cockatoo");

cout << "Now no cockatoos" << endl;

for_each(Birds.begin(), Birds.end(), PrintIt);

}

 

输出是:

  Original list with cockatoos cockatoo galah cockatoo rosella corella Now no cockatoos galah rosella corella

 

 

--------------------------------------------------------------------------------

 

16.使用STL通用算法remove()从list中删除元素

 

通用算法remove()使用和list的成员函数不同的方式工作。一般情况下不改变容器的大小。

/*

|| Using the generic remove algorithm to remove list elements

*/

#include <string>

#include <list>

#include <algorithm>

 

PrintIt(string& AString) { cout << AString << endl; }

 

int main (void)

{

    list<string> Birds;

    list<string>::iterator NewEnd;

 

    Birds.push_back("cockatoo");

    Birds.push_back("galah");

    Birds.push_back("cockatoo");

    Birds.push_back("rosella");

    Birds.push_back("king parrot");

 

    cout << "Original list" << endl;

    for_each(Birds.begin(), Birds.end(), PrintIt);

 

    NewEnd = remove(Birds.begin(), Birds.end(), "cockatoo");

 

    cout << endl << "List according to new past the end iterator" << endl;

    for_each(Birds.begin(), NewEnd, PrintIt);

 

    cout << endl << "Original list now. Care required!" << endl;

    for_each(Birds.begin(), Birds.end(), PrintIt);

}

 

输出结果将为:

Original list

cockatoo

galah

cockatoo

rosella

king parrot

 

List according to new past the end iterator

galah

rosella

king parrot

 

Original list now. Care required!

galah

rosella

king parrot

rosella

king parrot

通用remove()算法返回一个指向新的list的结尾的iterator。从开始到这个新的结尾(不含新结尾元素)的范围 包含了remove后剩下所有元素。你可以用list成员函数erase函数来删除从新结尾到老结尾的部分。

 

 

--------------------------------------------------------------------------------

 

17.使用STL通用算法stable_partition()和list成员函数splice()来划分一个list

 

使用STL通用算法stable_partition()和list成员函数splice()来划分一个list

  我们将完成一个稍微有点复杂的例子。它演示STL通用算法stable_partition()算法和一个list成员函数 splice()的变化。注意函数对象的使用和没有使用循环。 通过简单的语句调用STL算法来控制。

stable_partition()是一个有趣的函数。它重新排列元素,使得满足指定条件的元素排在 不满足条件的元素前面。它维持着两组元素的顺序关系。

 

splice 把另一个list中的元素结合到一个list中。它从源list中删除元素。

 

在这个例子中,我们想从命令行接收一些标志和四个文件名。文件名必须’按顺序出现。通过使用stable_partition() 我们可以接收和文件名混为任何位置的标志,并且不打乱文件名的顺序就把它们放到一起。

 

由于记数和查找算法都很易用,我们调用这些算法来决定哪个标志被设置而哪个标志未被设置。 我发现容器用来管理少量的象这样的动态数据。

 

/*

|| Using the STL stable_partition algorithm

|| Takes any number of flags on the command line and

|| four filenames in order.

*/

#include <string>

#include <list>

#include <algorithm>

 

PrintIt ( string& AString { cout << AString << endl; }

 

class IsAFlag {

public:

    bool operator () (string& PossibleFlag) {

        return PossibleFlag.substr(0,1)=="-";

    }

};

 

class IsAFileName {

public:

    bool operator () (string& StringToCheck) {

        return !IsAFlag()(StringToCheck);

    }

};

 

class IsHelpFlag {

public:

    bool operator () (string& PossibleHelpFlag) {

        return PossibleHelpFlag=="-h";

    }

};

 

int main (int argc, char *argv[]) {

 

    list<string> CmdLineParameters; // the command line parameters

    list<string>::iterator StartOfFiles; // start of filenames

    list<string> Flags; // list of flags

    list<string> FileNames; // list of filenames

 

    for (int i = 0; i < argc; ++i)

    CmdLineParameters.push_back(argv[i]);

 

        CmdLineParameters.pop_front(); // we don't want the program name

 

    // make sure we have the four mandatory file names

    int NumberOfFiles(0);

    count_if(CmdLineParameters.begin(), CmdLineParameters.end(), IsAFileName(), NumberOfFiles);

 

    cout << "The " << (NumberOfFiles == 4 ? "correct " : "wrong ") << "number (" << NumberOfFiles << ") of file names were specified" << endl;

 

 // move any flags to the beginning

    StartOfFiles = stable_partition(CmdLineParameters.begin(), CmdLineParameters.end(), IsAFlag());

 

    cout << "Command line parameters after stable partition" << endl;

    for_each(CmdLineParameters.begin(), CmdLineParameters.end(), PrintIt);

 

    // Splice any flags from the original CmdLineParameters list into Flags list.

    Flags.splice(Flags.begin(), CmdLineParameters, CmdLineParameters.begin(), StartOfFiles);

 

    if (!Flags.empty()) {

        cout << "Flags specified were:" << endl;

        for_each(Flags.begin(), Flags.end(), PrintIt);

    }

    else {

        cout << "No flags were specified" << endl;

    }

 

    // parameters list now contains only filenames. Splice them into FileNames list.

    FileNames.splice(FileNames.begin(), CmdLineParameters, CmdLineParameters.begin(), CmdLineParameters.end());

 

    if (!FileNames.empty()) {

        cout << "Files specified (in order) were:" << endl;

        for_each(FileNames.begin(), FileNames.end(), PrintIt);

    }

    else {

        cout << "No files were specified" << endl;

    }

 

    // check if the help flag was specified

    if (find_if(Flags.begin(), Flags.end(), IsHelpFlag())!=Flags.end()) {

        cout << "The help flag was specified" << endl;

    }

 

    // open the files and do whatever you do

 

}

给出这样的命令行:

test17 -w linux -o is -w great

 

输出是:

 

The wrong number (3) of file names were specified

Command line parameters after stable partition

-w

-o

-w

linux

is

great

Flags specified were:

-w

-o

-w

Files specified (in order) were:

linux

is

great

 

 

 

--------------------------------------------------------------------------------

 

18 结论

 

  我们仅仅简单的谈了谈你可以用list做的事情。我们没有说明一个对象的用户定义类,虽然这个不难。

 

  如果你懂了刚才说的这些算法背后的概念,那么你使用剩下的那些算法就应该没有问题了。使用STL 最重要的东西就是得到基本理论。

 

  STL的关键实际上是iterator。STL算法作为参数使用iterator,他们指出一个范围,有时是一个范围, 有时是两个。STL容器支持iterator,这就是为什么我们说 list<int>::iterator, 或 list<char>::iterator, 或 list<string>::iterator.

 

  iterator有很好的定义继承性。它们非常有用。某些iterator仅支持对一个容器只读,某些 仅支持写,还有一些仅能向前指,有一些是双向的。有一些iterator支持对一个容器的随机存取。

 

  STL算法需要某个iterator作为“动力” 如果一个容器不提供iterator作为“动力”,那么这个算法将无法编译。例如,list容器仅提供双向的iterator。通常的sort()算法需要随机存取的iterator。这就是为什么我们需要一个特别的list成员函数sort()。

 

  要合适的实际使用STL,你需要仔细学习各种不同的iterator。你需要知道每种容器都支持那类iterator。 你还需要知道算法需要那种iterator,你当然也需要懂得你可以有那种iterator。

 

在field中使用STL

    去年,我曾用STL写过几个商业程序。它在很多方面减少了我的工作量,也排除了很多逻辑错误。

    最大的一个程序有大约5000行。可能最惊人的事情就是它的速度。它读入并处理一个1-2兆的报告文件仅花大约20秒。我是在linux上用gcc2.7.2开发的,现在运行在HP-UX机器上。它一共用了大约50和函数对象和很多容器,这些容器的大小从小list到一个有14,000个元素的map都有。

    一个程序中的函数对象是处于一个继承树中,顶层的函数对象调用低层的函数对象。我大量的使用STL算法for_each() ,find(),find_if(),count()和count_if(),我尽量减少使用程序内部的函数,而使用STL的算法调用。

    STL倾向于自动的把代码组织成清晰的控制和支持模块。通过小心使用函数对象并给它们起有意义的名字,我使它们在我的软件的控制流中流动。

    还有很多关于STL编程要知道的东西,我希望你通过这些例子可以愉快的工作。

    参考数目中的两本书在web上都有勘误表,你可以自己改正它们。

    Stroustrup在每一章后面都有个建议栏,特别是对于出学者有用。正本书比早期的版本更加健谈。它也更大了。书店里还可以找到其他几本关于STL的教科书。去看看,也许你能发现什么。

 

BZOJ 1098([POI2007]办公楼biu-链表优化Dfs)

1098: [POI2007]办公楼biu

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 640  Solved: 254
[Submit][Status][Discuss]

Description

一些员工,每个人知道另外一些人的电话号码。假如A知道B的电话,B也一定知道A的电话号。上司想把这些员工分到尽可能多的办公楼里去。但是,如果A和B不在同一办公楼内,A和B就必须有对方的电话号码。求这些员工最多能够被分到多少办公楼内,并升序输出每个办公楼内的员工人数。

Input

第一行包含两个整数N(2<=N<=100000)和M(1<=M<=2000000)。职员被依次编号为1,2,……,N. 以下M行,每行包含两个正数A和B(1<=A<b<=n),表示职员a和b拥有彼此的电话号码。 

Output

包含两行。第一行包含一个数S,表示FGD最多可以将职员安置进的办公楼数。第二行包含S个从小到大排列的数,中间用空格隔开,表示每个办公楼里安排的职员数。

Sample Input

7 16

1 3

1 4

1 5

2 3

3 4

4 5

4 7

4 6

5 6

6 7

2 4

2 7

2 5

3 5

3 7

1 7



Sample Output

3

1 2 4



HINT

FGD可以将职员4安排进一号办公楼,职员5和职员7安排进2号办公楼,其他人进3号办公楼。

首先求出原图补图,则要求转化为-不同办公楼的人不连边。

于是想到求其补图连通块-显然补图是稠密图,会T

这题要用链表优化Dfs.

正常情况下我们从Node 1枚举到Node N ,会TLE

所有不妨建立链表,当一个元素走后便删掉

这样效率便转化为O(n+m)

Ps:这题用cin和scanf效率差很多



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<queue>
#include<list>
using namespace std;
#define MAXN (100000+10)
#define MAXM (2000000+10)
int n,m;
int size=0,edge[MAXM*2],pre[MAXM],next[MAXM*2];
struct link
{
	int pre,next;
}l[MAXN];
void del(int x)
{
	l[l[x].pre].next=l[x].next;
	l[l[x].next].pre=l[x].pre;
}
queue<int> q;
void addedge(int u,int v)
{
	edge[++size]=v;
	next[size]=pre[u];
	pre[u]=size;
}
bool b[MAXN],q_b[MAXN];
int z[MAXN],siz_z=0;
void bfs()
{
	memset(b,0,sizeof(b));
	memset(q_b,0,sizeof(q_b));
	while (l[0].next)
	{
		int now=l[0].next,ans=1;
		del(now);
		q.push(now);q_b[now]=1;
		//cout<<now<<endl; //00x
		while (!q.empty())
		{
			int u=q.front();q.pop();
			for (int p=pre[u];p;p=next[p]) b[edge[p]]=1;
			for(int i=l[0].next;i;i=l[i].next)
			{
				if (!b[i]&&!q_b[i])
				{
					q_b[i]=1;
					q.push(i);//cout<<v<<endl;  //0xx
					ans++;
					del(i);
				}
			}
			for (int p=pre[u];p;p=next[p]) b[edge[p]]=0;
		//	cout<<endl;
		}
		z[++siz_z]=ans;
	}
}
int main()
{
//	freopen("bzoj1098.in","r",stdin);
	memset(pre,0,sizeof(pre));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);addedge(v,u);
	}
	for (int i=1;i<=n;i++) {l[i-1].next=i;l[i].pre=i-1;} l[n].next=0;
	bfs();
	sort(z+1,z+1+siz_z);
	printf("%dn",siz_z);
	if (siz_z>0) {for (int i=1;i<siz_z;i++) printf("%d ",z[i]);printf("%d",z[siz_z]);	}
	return 0;
}

HDU 1234(开门人和关门人-scanf解决带注释数字读入)

开门人和关门人

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7841    Accepted Submission(s): 4066



Problem Description
每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签 
到、签离记录,请根据记录找出当天开门和关门的人。 
 


Input
测试输入的第一行给出记录的总天数N ( > 0 )。下面列出了N天的记录。 
每天的记录在第一行给出记录的条目数M ( > 0 ),下面是M行,每行的格式为 

证件号码 签到时间 签离时间 

其中时间按“小时:分钟:秒钟”(各占2位)给出,证件号码是长度不超过15的字符串。

 


Output
对每一天的记录输出1行,即当天开门和关门人的证件号码,中间用1空格分隔。 
注意:在裁判的标准测试输入中,所有记录保证完整,每个人的签到时间在签离时间之前, 
且没有多人同时签到或者签离的情况。 
 


Sample Input
3 1 ME3021112225321 00:00:00 23:59:59 2 EE301218 08:05:35 20:56:35 MA301134 12:35:45 21:40:42 3 CS301111 15:30:28 17:00:10 SC3021234 08:00:00 11:25:25 CS301133 21:45:00 21:58:40
 


Sample Output
ME3021112225321 ME3021112225321 EE301218 MA301134 SC3021234 CS301133
 


Source
 


Recommend
JGShining
 

利用Scanf可以解决时间的读入

%d:%d:%d的占位符

占位符中如果用符号,则表示读取这个符号,但不做任何事

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<functional>
#include<algorithm>
#include<cctype>
#include<iostream>
using namespace std;
int t,n;
struct ID
{
	char s[16];
	int in1,in2,in3,out1,out2,out3;
	int intime(){return in1*3600+in2*60+in3;}
	int outtime(){return out1*3600+out2*60+out3;}
	friend bool operator<(ID a,ID b){return a.intime()<b.intime();}
	friend bool operator>(ID a,ID b){return a.outtime()>b.outtime();}

}p,amin,amax;
int main()
{
	cin>>t;
	while (t--)
	{
		int n;
		cin>>n;
		scanf("%s %d:%d:%d %d:%d:%d",p.s,&p.in1,&p.in2,&p.in3,&p.out1,&p.out2,&p.out3);
		amin=amax=p;
		for (int i=2;i<=n;i++)
		{
			scanf("%s %d:%d:%d %d:%d:%d",p.s,&p.in1,&p.in2,&p.in3,&p.out1,&p.out2,&p.out3);
			if (p<amin) amin=p;
			if (p>amax) amax=p;
		}
		printf("%s %sn",amin.s,amax.s);
	}
	return 0;
}


POJ 1113(Wall-Quickhull)

Language:
Wall
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 24604   Accepted: 8183

Description

King想在自己的n个城堡外建Wall,使Wall与任一城堡距离至少为L且能围住它的城堡. 


求Wall最短长度. 

Input

第一行为 N (3 <= N <= 1000) 和 L(1 <= L <= 1000).
接下来 N 行,每行为城堡坐标Xi,Yi (-10000 <= Xi, Yi <= 10000).

Output

输出一行Wall最短长度.

Sample Input

9 100
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200

Sample Output

1628

Hint

结果四舍五入就可以了

Source

易证Wall最短长度=对城堡求凸包的周长+2πL

这里介绍一个凸包求法QuickHull

备注Quickhull-

s表示向量CACB的叉积(在上一求得,用于求距离),初始化为0

用[l,r]表示点集区间,

有2个要点

1.A,B , C的关系

(1)

(2)


2.i,j的调换

可从下图看出










#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<functional>
#include<algorithm>
#include<cctype>
using namespace std;
#define MAXN (1000+10)
#define MAXXi (10000+10)
#define eps (1e-10)
const double pi=3.1415926;
int sqr(int x) {return x*x;}
struct P
{
	int x,y;
	P(){}
	P(int _x,int _y):x(_x),y(_y){}
	friend istream& operator>>(istream &cin,P &a)
	{
		cin>>a.x>>a.y;
		return cin;
	}
	friend bool operator<(const P a,const P b){return (a.x==b.x)?a.y<b.y:a.x<b.x;}
	friend bool operator>(const P a,const P b){return (a.x==b.x)?a.y>b.y:a.x>b.x;}
}a[MAXN],st[MAXN];
double dis(P A,P B)
{
	return sqrt((double)sqr(A.x-B.x)+sqr(A.y-B.y));
}
struct V
{
	int x,y;
	V(){}
	V(int _x,int _y):x(_x),y(_y){}
	V(P a,P b):x(b.x-a.x),y(b.y-a.y){}
	friend int operator*(V a,V b)
	{
		return a.x*b.y-a.y*b.x;
	}
};
int n,l,size=0;
double s[MAXN]={0.0};
void hull(int l,int r,P A,P B)
{
	int p=l;
	for (int k=l;k<=r;k++)
		if (s[p]<s[k]||s[p]==s[k]&&a[p]<a[k]) p=k;
	P C=a[p];
	int i=l-1,j=r+1;
	for (int k=l;k<=r;k++)
	{
		s[++i]=V(a[k],A)*V(a[k],C);
		if (s[i]>0) /*Right*/ swap(a[i],a[k]); else i--;
	}
	for (int k=r;k>=l;k--)
	{
		s[--j]=V(a[k],C)*V(a[k],B);
		if (s[j]>0) /*Right*/ swap(a[j],a[k]); else j++;
	}
	if (l<=i) hull(l,i,A,C);
	st[++size]=C;
	if (j<=r) hull(j,r,C,B);
}
int main()
{
//	freopen("poj1113.in","r",stdin);
	cin>>n>>l;
	for (int i=1;i<=n;i++)
		cin>>a[i];
	int pmin=1,pmax=1;
	for (int i=2;i<=n;i++)
	{
		if (a[i]<a[pmin]) pmin=i;
		if (a[i]>a[pmax]) pmax=i;
	}
	swap(a[1],a[pmin]);swap(a[n],a[pmax]);
	st[++size]=a[1];
	hull(2,n,a[1],a[1]);
//	for (int i=1;i<=size;i++) cout<<st[i].x<<' '<<st[i].y<<' '<<endl;
	double ans=0;
	for (int i=1;i<=size;i++) ans+=dis(st[i],st[i+1<=size?i+1:1]);
	cout.setf(ios::fixed);
	cout.precision(0);
	cout<<ans+2*pi*l<<endl;
	return 0;
}

POJ 1741(男人八题-Tree-点分治)

Language:
Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 6982   Accepted: 2010

Description

给定一棵 N (1 N 10000) 个结点的带权(≤1000)树,定义
dist(u, v) 为 u, v 两点间的最短路径长度, 路径的长度定义为路径上所有边的权和。再给定一个 K (1 K 10 ) ,如果对于不同的两个结点 a, b ,如果满 足 dist
(a, b) K ,则称 (a, b) 为合法点对。 求合法点对个数。

Input

有很多数据. 每组数据第一行为 n, k. (n<=10000) 接下来 n-1 行为 u,v,w, 表示u和v之间有一条权为w的边. 
数据以‘0 0’结尾. 

Output

对每组数据输出一行合法点对个数.

Sample Input

5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0

Sample Output

8

Source

漆子超的论文里有该题的详细解题报告

在这里简单说说树链剖分中center_node的选取。

center_node为一棵子树中的一个能使其为根节点时,其的子树的最大结点数最小的的结点。

也就是使子树的max_siz最小

因为换了root,必须用b记录,防止走到子树外去。


重儿子:一个节点的儿子中siz最大的那个(hson)


#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (10000+10)
int n,k;
int edge[MAXN*2],pre[MAXN],next[MAXN*2],weight[MAXN*2],size=0;
bool b[MAXN];
void addedge(int u,int v,int w)
{
	edge[++size]=v;
	weight[size]=w;
	next[size]=pre[u];
	pre[u]=size;
}
int dis[MAXN],deep[MAXN],siz[MAXN],max_sub_siz[MAXN],tot;
int que[MAXN],q_n;
void get_center_dfs(int u,int fa)
{
	siz[u]=1;que[++q_n]=u;max_sub_siz[u]=0;
	for (int p=pre[u];p;p=next[p])
	{
		int &v=edge[p];
		if (v!=fa&&!b[v])
		{
			get_center_dfs(v,u);siz[u]+=siz[v];
			max_sub_siz[u]=max(max_sub_siz[u],siz[v]);
		}
	}

}
int get_center(int u,int fa)
{
	int minhson=n,mini=0;q_n=0;
	get_center_dfs(u,fa);
	for (int i=1;i<=q_n;i++)
	{
		max_sub_siz[que[i]]=max(max_sub_siz[que[i]],q_n-siz[que[i]]);
		if (minhson>max_sub_siz[que[i]])
		{
			minhson=max_sub_siz[que[i]];
			mini=que[i];
		}
	}
	return mini;
}
void getdis(int u,int d,int fa)
{
	dis[++tot]=d;
	for (int p=pre[u];p;p=next[p])
	{
		int &v=edge[p];
		if (v!=fa&&!b[v])
		{
			getdis(v,d+weight[p],u);
		}
	}
}
int count_dis(int l,int r)
{
	int i=l,j=r,ans=0;sort(dis+l,dis+r+1);
	while (i<j)
	{
		if (dis[i]+dis[j]<=k) ans+=j-(i++);
		else j--;
	}
	return ans;
}
int dfs_main(int u,int fa)
{
	int root=get_center(u,fa),ans=0;
	tot=0;
	b[root]=1;
	for (int p=pre[root];p;p=next[p]) //root
	{
		int &v=edge[p];
		if (v!=fa&&!b[v])
		{
			int l=tot+1;
			getdis(v,weight[p],root);
			ans-=count_dis(l,tot);
		}
	}
	dis[++tot]=0;
	ans+=count_dis(1,tot);
	for (int p=pre[root];p;p=next[p])
	{
		int &v=edge[p];
		if (v!=fa&&!b[v])
		{
			ans+=dfs_main(v,root);
		}
	}
	return ans;
}
int main()
{
//	freopen("poj1741.in","r",stdin);
	while (scanf("%d%d",&n,&k)&&(n+k))
	{
		memset(pre,0,sizeof(pre));size=0;
		memset(b,0,sizeof(b));
		int u,v,w;
		for (int i=1;i<n;i++)
		{
			scanf("%d%d%d",&u,&v,&w);
			addedge(u,v,w);addedge(v,u,w);
		}
		cout<<dfs_main(edge[1],0)<<endl;
	}
	return 0;
}

POJ 1222(Gauss消元xor版)

EXTENDED LIGHTS OUT
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 5182   Accepted: 3403

Description

Lights Out就是下图的游戏,给你一个5*6的矩阵. 


你的目标是把灯全关上. 



0表示关,1表示开.

Input

第一行为数据组数T.
对于每组数据,输入1个5*6的矩阵.

Output

对于每组数据,输出一行 "PUZZLE #m".接下来为还原矩阵.

Sample Input

2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0

Sample Output

PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1

Source

就是Gauss消元的xor版本.

显然若 a1 xor a2 xor a3..=an

             b1 xor b2 xor b3..=bn

        则 (a1 xor b1) xor (a2 xor b2)..=an xor an

满足消元性质

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<functional>
using namespace std;
const int n=5,m=6;
bool inside(int x){return (x>=0)&&(x<31);}
struct E
{
	int a[31];
	int& operator[](int p){static int t;if (inside(p)) return a[p]; else return t;}
	friend E operator^(E a,E b)
	{
		for (int i=0;i<31;i++) a[i]^=b[i];
		return a;
	}
};
struct M
{
	E a[30];
	E& operator[](int p){return a[p];}
	M()
	{
	//	memset(a,sizeof(a),0);
		for (int i=0;i<30;i++)
			for (int j=0;j<31;j++) a[i][j]=0;
		for(int i=0;i<n*m;i++)
		{
			a[i][i]=a[i][i+6]=a[i][i-6]=1;
			if (i%6) a[i][i-1]=1;
			if (i%6<5) a[i][i+1]=1;

		}
	}
	void gauss()
	{
		int i=0,j=0,n=30,m=31;
		while (i<n&&j<m)
		{
//			print();
			int maxi=i;
			for(int k=i+1;k<n;k++) if (a[k][j]>a[maxi][j]) maxi=k;
			if (a[maxi][j]!=0)
			{
				swap(a[maxi],a[i]);
				for(int k=i+1;k<n;k++)
					if (a[k][j]!=0) a[k]=a[k]^a[i];
			}
			i++;j++;
		}
		for(int i=28;i>=0;i--)
		{
			for(int j=i+1;j<30;j++) if (a[i][j]) {a[i][j]=0;a[i][30]^=a[j][30];	}
		}
		for (int i=0;i<30;i++)
		{
			cout<<a[i][30];
			if (i%6==5) cout<<endl; else cout<<' ';
		}
	}
	void print()
	{
		for (int i=0;i<30;i++)
		{
			for (int j=0;j<31;j++) cout<<a[i][j]<<' ';
			cout<<endl;
		}
		cout<<"--------------------------------------------------n";
		system("pause");
	}


}EM;
int main()
{
//	freopen("poj1222.in","r",stdin);
	int tt;
	cin>>tt;
	for(int t=1;t<=tt;t++)
	{
		EM=M();
		for(int i=0;i<n*m;i++) cin>>EM[i][30];
		cout<<"PUZZLE #"<<t<<endl;
		EM.gauss();


	}
	return 0;
}



fzu_noip 1040(继任者-离线排序插入+区间最值)

继任者

时限:1s内存:32M

★问题描述:

S开了家公司,他自己是老板,其余员工都有一名直系上级,每名员工都有对公司的忠诚度和能力值。S时不时会开除某名员工,由其下属中能力值大于这名员工的人中忠诚度最高的担任其职务。他想知道,若开除某名员工,该选谁担任其职务。A是B的下属是指,A的直系上级是B或B的下属。

★数据输入:

第一行输入T表示CASE数。接下来T组数据,每组数据第一行输入两个整数n,m(2<=n,m<=25000),表示有该公司包括S有n个人,有m组询问。员工按输入顺序从1到n-1编号,S编号为0。接下去1到n-1行,每行三个整数a,b,c(0<=a<=n-1,0<=b,c<=1000000)分别表示第i名员工的直系上级编号、忠诚度、能力值,每名员工的编号大于其上级的编号,且他们的忠诚度各不相同。接下去m行,每行一个整数q(1<=q<=n-1)表示询问若开除第q名员工应该选谁担任其职务。注意询问并没有真正开除员工,也就是说各个询问假设要开除的员工互不影响。

★结果输出:

对于每个询问输出一个数表示该选的员工的编号,若这样的员工不存在则输出-1。

输入示例

输出示例

1

3 2

0 100 99

1 101 100

1

2

2

-1

 本来是按B值对结点从大到小排序-然后按顺序插入线段树

因为插入前结点所对应的区间一定只有比父节点B值大的,因此直接输出A值最大的即可(线段树)

实际做法:暴力插入结点,直到找到根或找到比它A,B值都大(这样上司选它一定更优)的为止。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (25000+10)
#define MAXCi (1000000)
int n,m;
struct node
{
    int key,fim,fa,ans;
    node():ans(-1){}
    node(int _key,int _fim,int _fa):key(_key),fim(_fim),fa(_fa),ans(-1){}
}a[MAXN];
void update(int x)
{
     for (int now=a[x].fa;now;now=a[now].fa)
     {
         if (a[x].key>a[now].key&&(a[now].ans==-1||a[a[now].ans].fim<a[x].fim)) a[now].ans=x;
         else if (a[x].key<a[now].key&&a[x].fim<a[now].fim) break;
     }
}
int main()
{
    cin>>n>>m;
    for (int i=1;i<=n-1;i++)
    {
        cin>>a[i].fa>>a[i].fim>>a[i].key;update(i);
    }
    for (int i=1;i<=m;i++)
    {
        int p;
        cin>>p;
        cout<<a[p].ans<<endl;
    }
    return 0;
}

fzu_noip 1039(盖楼-线段树)

盖楼

时限:1s内存:32M

★问题描述:

S举办了一场盖楼比赛,有n位选手参赛,将这n位选手编号为1到n。比赛刚开始时第i位选手的房子的初始高度为Ai,每过一天该选手的房子高度增加Bi。S想知道比赛开始后T天编号为L到R的选手中,造的最高的房子高度为多少。

★数据输入:

输入数据的第一行为两个整数N,Q。(1<=N,Q<=30000)。接下来N行,表示每个选手的初始房子高度和房子每天增长高度,每行两个数Ai,Bi(1<=Ai,Bi<=10^9)。接下来Q行,表示Q个询问,每行3个数Li,Ri,Ti(1<=Li<=Ri<=N,0<=Ti<=1000000)。所有输入都是整数。

★结果输出:

对于每个询问输出一行一个整数,表示比赛开始后Ti天编号为Li到Ri的选手中造的房子的最大高度。

 

输入示例

输出示例

5 4

4 1

3 5

6 2

3 5

6 5

1 5 2

1 3 5

1 1 0

1 5 0

16

28

4

6

5 4

6 1

5 1

2 5

4 3

6 1

2 4 1

3 4 5

1 4 5

1 2 0

7

27

27

6

 

本来是半平面交+线段树合并(归并合并),暴力居然能过


const
   maxn=30000;
var
   n,q,i,j,l,r,p,t:longint;
   a,b:array[1..maxn] of longint;
begin
   read(n,q);
   for i:=1 to n do read(a[i],b[i]);
   for i:=1 to q do
   begin
      read(l,r,t);
      p:=b[l]*t+a[l];
      for j:=l+1 to r do
         if (p<b[j]*t+a[j]) then p:=b[j]*t+a[j];
      writeln(p);
   end;
end.