集训Day1

匆匆忙忙一天,还剩20分钟,简单总结一下做过的题

单调栈的性质
单调栈是一种特殊的栈,特殊之处在于栈内的元素都保持一个单调性。
假设下图是一个栈内元素的排列情况(单调递增的栈):

此时插入情况有两种:
(1)插入元素大于栈顶元素:
因为7 > 6,满足栈内元素单调递增的性质,所以可以直接插入7到栈顶

(2)当插入元素小于栈顶元素的时候,当插入3的时候,需要将栈顶的6,4弹出,在插入,例如:

这个会了,例题就简单了(必须明确理解)


功能
利用单调栈可以找出从左/右遍历第一个比它小/大的元素的位置
例如说:
现在有一个数组a[4] = {5,7,3,4},要你找出每一个元素左边最靠近它的最小元素的位置(下标+1),如果没有元素比它小,则输出0
此时我们会想到,从每一个数字开始想左边遍历,这是一个朴素的算法,我们就不再多说了。
我们要说的是怎么样利用单调栈来解决该问题
1.设计一个数组res[4],来保存结果
2.开一个栈,这个栈的性质是,当栈为空的时候,将对应的res[i] = 0;当栈顶元素是从左开始,输入的数中最小的那个的下标,如果进栈的元素小于或者等于a[栈顶元素],则输出0;如果大于,则输出栈顶元素+1。

下面上代码:

#include<bit/stdc++.h>
using namespace std;

int main() {
    //n表示要找的总数
    int n; cin >> n;
    //a用来保存输入的数据
    int* a = new int[n];
    //res_left用来保存对应的结果
    int* res_left = new int[n];
    stack<int>s;
    for (int i = 0; i < n; i++)cin >> a[i];
    //找出a[i]左边和右边最近的一个比他小的值的下标
    for (int i = 0; i < n; i++) {
        while (!s.empty() && a[i] <= a[s.top()])s.pop();
        if (s.empty())res_left[i] = 0;
        else res_left[i] = s.top() + 1;
        s.push(i);
    }
    //这个栈就是递减的一个,取最小值的时候,复杂度是O(1)
    for (int i = 0; i < n; i++) {
        cout << res_left[i] << " ";
    }
}

A. 圆环塔

题目描述

给出nn个圆环,每个圆环有内径aiai,外径bibi,高hihi。

圆环xx能放在圆环yy上仅当ay<bx≤byay<bx≤by,问这些圆环最多能搭多高。

输入格式

第一行一个整数n,表示有n个圆环 (1⩽n⩽100000)(1⩽n⩽100000)

接下来n行,每行3个整数,为内径aiai,外径bibi,高hi(1⩽ai,bi,hi⩽109,bi>ai)hi(1⩽ai,bi,hi⩽109,bi>ai)

输出格式

一行,一个整数,表示圆环塔的最大高度。

样例数据

input

3
1 5 1
2 6 2
3 7 3

output

6

input

4
1 2 1
1 3 3
4 6 2
5 7 1

output

4

 模板题,用单调栈来写,sort+结构体

#include<bits/stdc++.h>
using namespace std;
struct node
{
	int a,b,h;
}p[100200];
int n;
long long ans,sum;
bool mysort(node x,node y)
{
	if(x.b==y.b) return x.a>y.a;
	return x.b>y.b;
}
stack<int> s;
int main()
{
	freopen("standard.in","r",stdin);
	freopen("standard.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		long long aa,bb,cc;
		scanf("%lld%lld%lld",&aa,&bb,&cc);
		p[i]={aa,bb,cc};
	}
	sort(p+1,p+1+n,mysort);
	s.push(1);
	ans=sum=p[1].h ;
	for(long long i=2;i<=n;i++)
	{
		while(!s.empty()&&p[s.top()].a>=p[i].b )
		{
			sum-=p[s.top()].h;
			s.pop();
		}
		sum+=p[i].h;
		s.push(i);
		ans=max(ans,sum);
	}
	cout<<ans;
	return 0;
}

    

B. 乱头发节

题目描述

贤正的某 N 头奶牛 (1 <= N <= 80,000) 正在过乱头发节!由于每头牛都 意识到自己凌乱不堪的发型, 宁智贤希望统计出能够看到其他牛的头发的牛的数量。

每一头牛 i有一个高度 h[i] (1 <= h[i] <= 1,000,000,000)而且面向东方排成 一排(在我们的图中是向右)。因此,第i头牛可以看到她前面的那些牛的头, (即i+1, i+2,等等),只要那些牛的高度严格小于她的高度。

例如这个例子:

牛#1 可以看到她们的发型 #2, 3, 4 牛#2 不能看到任何牛的发型 牛#3 可以看到她的发型 #4 牛#4 不能看到任何牛的发型 牛#5 可以看到她的发型 6 牛#6 不能看到任何牛的发型!

让 c[i] 表示第i头牛可以看到发型的牛的数量;请输出 c[1] 至 c[N]的和。 如上面的这个例子,正确解是3 + 0 + 1 + 0 + 1 + 0 = 5。

输入格式

  • Line 1: 牛的数量 N。

  • Lines 2..N+1: 第 i+1 是一个整数,表示第i头牛的高度。

输出格式

Line 1: 一个整数表示c[1] 至 c[N]的和。

样例数据

input

6
10
3
7
4
12
2

output

5

直往右边看,比较一下,如果大于栈顶就pop重新来

简单题

#include<bits/stdc++.h>
using namespace std;
stack<int>s;
long long sum,n,m[88888];
int main()
{
	freopen("badhair.in","r",stdin);
	freopen("badhair.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&m[i]);
	}
	for(int i=1;i<=n;i++)
	{
		while(!s.empty()&&s.top()<=m[i])
		{
			s.pop();
		}
		sum+=s.size();	
		s.push(m[i]);
	}
	cout<<sum;
	return 0;
}

C. 排队

题目描述

现在有N(0<=N<=500 000)个人在一起排队,他们的身高分别为A1,...,AN(0<=Ai<=231},i=1~N)我们规定A能看到B当且仅当AB之间没有比A高的人,那么有多少对人能够相互看到呢?

输入格式

第一行一个非负整数N,第二行N个非负整数A1,...,AN,之间用空格分隔

输出格式

一行一个非负整数,表示相互能看到的人的对数

样例

样例输入1

2
2 2

样例输出1

1

样例输入2

3
3 2 1

样例输出2

2

多一个相等的情况,在考虑一种情况,并且不让他全部进栈

#include<bits/stdc++.h>
using namespace std;
int n,ans=0;
int a[500500];
stack<int>  st;
void init()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
}
void work()
{
	st.push(a[1]);
	for(int i=2;i<=n;i++)
	{
		int k=1;
		while(!st.empty())
		{
			if(a[i]>st.top())    ans++,st.pop();
			else if(a[i]==st.top())  ans++,k++,st.pop();
			else if(a[i]<st.top())  {ans++;break;} 
		}
		for(int j=1;j<=k;j++)
			st.push(a[i]);
	}
}
void print()
{
	printf("%d",ans);
}
int main()
{
    freopen("stack.in","r",stdin);
    freopen("stack.out","w",stdout);
    init();
    work();
    print();
    return 0;
} 

D. 子序列累加和

题目描述

小x在学习数列。他想到一个数学问题:

现在有N个数的数列。现在你定义一个子序列是数列的连续一部分,子序列的值是这个子序列中最大值和最小值之差。

给你这N个数,小x想知道所有子序列的值的累加和是多少。

输入格式

第一行一个整数N (2 ≤ N ≤ 300 000)

接下来N行,每行一个整数Ai,表示数列的值

输出格式

一个整数,所求的子序列值的累加和。

样例数据

input

4
3
1
7
2

output

31

数据规模与约定

40% N<=3000

100% 0<Ai<=100000000

时间限制:1s1s

空间限制:256MB256MB

CF817DCF817D 题解

这题难在预处理和乘法原理上,题解链接如上

E. Largest Rectangle in a Histogram

题目描述

直方图是由在公共基线对齐的一系列矩形组成的多边形。矩形具有相同的宽度,但可能具有不同的高度。例如,左图显示了由高度为 2、1、4、5、1、3、3 的矩形组成的直方图,以单位测量,其中 1 是矩形的宽度:

通常,直方图用于表示离散分布,例如文本中字符的频率。请注意,矩形的顺序(即它们的高度)很重要。计算直方图中与公共基线对齐的最大矩形的面积。右图显示了所描绘直方图的最大对齐矩形。

这道题让求直方图中最大的矩形

输入和输出

输入

输入包含几个测试用例。每个测试用例描述一个直方图,并以整数 n 开头,表示它由多少个矩形组成。您可以假设 1<=n<=100000。然后跟随 n 个整数 h1,...,hn,其中 0<=hi<=1000000000。这些数字以从左到右的顺序表示直方图矩形的高度。每个矩形的宽度为 1。最后一个测试用例的输入后面跟着一个零。

输入包含多组数据。每组数据包含一行,第一个正整数N表示有N个矩形,接下来N个正整数描述其高度。 数据以N=0结束。 数据范围参看英文题面。

输出

对于单行上的每个测试用例输出指定直方图中最大矩形的面积。请记住,此矩形必须与公共基线对齐。

对于每组数据输出一行包含一个正整数,表示该组数据的答案。

样例

样本输入

7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0

样本输出

8
4000

这个题详细讲

首先栈是空的所以可以直接将2入栈,

因为2可以拓展,只要有能拓展的可能都可入栈;

然后因此只要比栈顶大的元素都可以入栈,他们的宽度都为1;

然后读到第二个数1;此时2已经没有拓展的可能了;

记录它此时的面积(ans=max(ans,(long long)width*q.top();)

然后向下拓展(此时就要将1入栈因为它可以向后拓展);

然后读入4,5,宽度是1;此时又一次读到了比4,5都小的1,

wid[q.size()]表示的就是当前栈中的元素的宽,

当高度减小(额就是有元素出栈,要更新面积)就可以调用,同时累加起来,

方便求“更矮更长”的矩形面积

然后就记录他们的面积然后向后拓展,然后以此类推,

然后这里面有一个小细节就是让我们读入数组的最后一位的下一位变为零

然后它再回来记录面积的话可以记录每一个在栈内的面积;

这样我们就找到了整张图的最大连续面积;

思路大致如上,但是由于这个题的抽象,一开始我很难理解,把样例带入感受,结合代码

打标了的是手写栈,不好理解

#include<bits/stdc++.h>
using namespace std;
int n,h[100006],wid[100006],s[100006],top;
long long ans,width;//注意要开longlong
stack<long long>q;
int main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
    while(cin>>n)
    {
        if(n==0)return 0;
        memset(s,0,sizeof(s));
        memset(h,0,sizeof(h));
        memset(wid,0,sizeof(wid));
        top=0;ans=0;//记得清零!!!
        for(int i=1;i<=n;i++)
        {
        	cin>>h[i];
		}
        h[++n]=0;//加入一个高度为0的点,可以在最后统计答案,不会遗漏
        for(int i=1;i<=n;i++)
        {
//            int width=0;
//            while(top&&h[s[top]]>h[i])
//            {
//                width+=wid[top];
//                ans=max(ans,(long long)width*h[s[top]]);
//                top--;
//            }
//            s[++top]=i;
//            wid[top]=width+1;
			width=0;
			while(!q.empty()&&q.top()>=h[i])
			{
				width+=wid[q.size()];
				ans=max(ans,(long long)width*q.top());
				q.pop();
			}	
			q.push(h[i]);
			wid[q.size()]=width+1;
        }
        cout<<ans<<endl;
    }
}

1.

当前栈为空,所以不进入while,只把2入栈,此时wid【1】=1;
2.

高度为1的元素准备进栈,但必须从栈顶开始删除高度大于或等于1的矩形,

因为2已经不可能延续到当前矩形。要删除(2)这个元素,

先求此时的width 为wid【1】,高是2,更新最大矩形面积为2x1=2,ans=2;

然后把它的宽度1累加到当前高度为1的准备进栈的矩形,然后进栈,当前栈为(1)

wid【1】更新为2;

3.

高度为4的元素进栈,当前栈为(1,4);

此时可得wid【2】=1;

4

高度为5的元素进栈,当前栈为(1,4,5)

此时wid【3】=1;

5(关键一步)

(1)高度为1的元素准备进栈,1<5

width=1,q.top()=5;

更新最大矩形面积为5x1=5,ans=max(2,5)=5;

删除(5)这个元素,还有(1,4);

(2)再和4比较,

此时width=1+1=2;q.top()=4;

更新最大矩形面积为4x2=8,ans=max(5,8)=8;

删除4,还有(1)

(3)和1比较,

width=2+wid【1】=4;q.top()=1;

1x4=4<8,不必更新ans;

删除1,栈为空;

当前栈为(1)

wid[1]更新成5;

6.

高度为3的元素进栈,当前栈为(1,3)


7

高度为3的元素准备进栈,

width=1,q.top()=3;

ans=max(3,8)=8

删除(3)

wid【2】=2;

8

h【++n】=0就是又加了一个小矩形

以此来清空栈,避免少

(1)0<3

        width=2,q.top()=3;

ans=max(2*3,8)=8;

(2)0<1

width=wid[1]+2=7;

ans=max(1*7,8)=8;

.

F. City Game

Description

这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。

现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。

但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你S两银子。

Input Format

第一行两个整数N,M,表示矩形土地有N行M列。

接下来N行,每行M个用空格隔开的字符'F'或'R',描述了矩形土地。

Output Format

输出一个整数,表示你能得到多少银子,即(3*最大'F'矩形土地面积)的值。

Sample Input

5 6
R F F F F F
F F F F F F
R R R F F F
F F F F F F
F F F F F F

Sample Output

45

非常easy   和上一题大同小异 不多说了

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int n,m;
char a[maxn][maxn];
int h[maxn],w[maxn];
stack<int>que;
int work()
{
	while(!que.empty()) que.pop();
	h[m+1]=0;
	int maxx=0;
	for(int i=1;i<=m+1;i++)
	{
		int width=0;
		while(!que.empty()&&h[que.top()]>=h[i])
		{
			width+=w[que.top()];
			maxx=max(maxx,h[que.top()]*width);
			que.pop();
		}
		que.push(i);
		w[i]=width+1;
	}
	return maxx;
}
int main()
{
	freopen("_.in","r",stdin);
	freopen("_.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='F') h[j]+=1;
			else h[j]=0;
		}
		ans=max(ans,work());
	}
	printf("%d",ans*3);
	return 0;
} 

  

G. 窗户

题目描述

给你一个长度为 N 的数组,一个长为 K 的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:

你的任务是找出窗口在各位置时的 max value,min value.

输入格式

第 1 行 n,k,

第 2 行为长度为 n 的数组

输出格式

2 行,

第 1 行每个位置的 min value,

第 2 行每个位置的 max value

样例数据

input

8 3 
1 3 -1 -3 5 3 6 7

output

-1 -3 -3 -3 3 3 
3 3 5 5 6 7

双端队列的运用————只讲min了,max同理

for(int i=1;i<=n;i++)
	{
		while(minn.empty()==false&&minn.front().val>=num[i])	minn.pop_front();
		minn.push_front(node({num[i],i}));
		while(minn.empty()==false&&i-minn.back().id>=len) minn.pop_back();
		ans[i][1]=minn.back().val;
	}

一行一行看

1:   准备进队的元素和队首比较,小于的话就让旧的出队,新的进队,维护一个最小值在队首

2:   新元素进队

3:边界范围,进队的时候也让下标进队了,所以队首减去队尾要在合法范围内,

        如果不在要弹出————体现双端队列的好处

for(int i=len;i<n;i++) 
		printf("%lld ",ans[i][1]);
	printf("%lld\n",ans[n][1]);

输出的时候直接从len开始

因为是一个窗口,一开始的时候就已将他维护成一个下降队列了;注意空格; 

#include <bits/stdc++.h>
using namespace std;
struct node
{
	long long val,id;
};
deque <node> minn,maxx;
long long  n,len;
long long num[1000010];
long long ans[1000010][3];
int main()
{
	freopen("window.in","r",stdin);
	freopen("window.out","w",stdout);
	cin>>n>>len;
	for(int i=1;i<=n;i++)
		scanf("%lld",&num[i]);
	for(int i=1;i<=n;i++)
	{
		while(minn.empty()==false&&minn.front().val>=num[i])	minn.pop_front();
		minn.push_front(node({num[i],i}));
		while(minn.empty()==false&&i-minn.back().id>=len) minn.pop_back();
		ans[i][1]=minn.back().val;
	}
		for(int i=1;i<=n;i++)
	{
		while(maxx.empty()==false&&maxx.front().val<=num[i])	maxx.pop_front();
		maxx.push_front(node({num[i],i}));
		while(maxx.empty()==false&&i-maxx.back().id>=len) maxx.pop_back();
		ans[i][2]=maxx.back().val;
	}
	for(int i=len;i<n;i++) 
		printf("%lld ",ans[i][1]);
	printf("%lld\n",ans[n][1]);
	for(int i=len;i<n;i++) 
		printf("%lld ",ans[i][2]);
	printf("%lld\n",ans[n][2]);
	return 0;
}

H. 最大子段和(带长度限制)

Description

输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大。

例如 1,-3,5,1,-2,3

当m=4时,S=5+1-2+3=7

当m=2或m=3时,S=5+1=6

Input Format

第一行两个数n,m

第二行有n个数,要求在n个数找到最大子序和

Output Format

一个数,数出他们的最大子序和

Sample Input

6 4
1 -3 5 1 -2 3

Sample Output

7

利用前缀和相减求区间和

答题思路不变

#include <bits/stdc++.h>
using namespace std;
int n,m;
long long  num[300010];
deque <int> Q;
long long sum[300010];
long long ans=-1e12;
int main()
{
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++)	
	{
		scanf("%lld",&num[i]);
		ans=max(ans,num[i]);
		sum[i]=sum[i-1]+num[i];
	}
	for(int i=1;i<=n;i++)
	{
		while(Q.size() && Q.front()<i-m) Q.pop_front();
		while(Q.size() && sum[Q.back()]>=sum[i]) Q.pop_back();
		Q.push_back(i);
		ans=max(ans,sum[i]-sum[Q.front()]);
	}
	printf("%lld",ans);
	return 0;
}

I. holiday

题目描述

经过几个月辛勤的工作,FJ决定让奶牛放假。

假期可以在1…N天内任意选择一段(需要连续),每一天都有一个享受指数W。但是奶牛的要求非常苛刻,假期不能短于P天,否则奶牛不能得到足够的休息;假期也不能超过Q天,否则奶牛会玩的腻烦。

FJ想知道奶牛们能获得的最大享受指数。

输入格式

第一行:N,P,Q.

第二行:N个数字,中间用一个空格隔开。

输出格式

一个整数,奶牛们能获得的最大享受指数。

样例数据

input

5 2 4
-9 -4 -3 8 -6

output

5

比上一道多了一个范围,直接处理掉就哦了

注意前缀和相减的时候长度问题;

#include <bits/stdc++.h>
using namespace std;
long long n,p,q;
long long ans=-1e12;
long long enjoy[100010];
long long sum[100010];
deque <long long > Q;
int main()
{
	freopen("holiday.in","r",stdin);
	freopen("holiday.out","w",stdout);
	cin>>n>>p>>q;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&enjoy[i]);
		sum[i]=sum[i-1]+enjoy[i];
	}
	for(int i=1;i<=n;i++)
	{
		if(i-p<1) continue;
		while(Q.empty()==false&&Q.front()<i-q) Q.pop_front();
		while(Q.empty()==false&&sum[Q.back()]>=sum[i-p]) Q.pop_back();
		Q.push_back(i-p);
		ans=max(ans,sum[i]-sum[Q.front()]);
	}
	printf("%lld",ans);
	return 0;
}

J. 树状数组 1 :单点修改,区间查询

题目描述

输入一个数列A1,A2….An(1<=N<=100000),在数列上进行M(1<=M<=100000)次操作,操作有以下两种:

(1) 格式为C I X,其中C为字符“C”,I和X(1<=I<=N,|X|<=10000)都是整数,表示把把a[I]改为X

(2) 格式为Q L R,其中Q为字符“Q”,L和R表示询问区间为[ L ,R] (1<=L<=R<=N),表示询问A[L]+…+A[R]的值。

输入格式

第一行输入N(1<=N<=100000),表述数列的长度;

接下来N行,每行一个整数(绝对值不超过10000)依次输入每个数;

接下来输入一个整数M(1<=M<=100000),表示操作数量,接下来M行,每行为C I X或者Q L R。

输出格式

对于每个Q L R 的操作输出答案。

input

5
1
2
3
4
5
3
Q 2 3
C 3 9
Q 1 4

output

5
16

树状数组:blog.csdn.net/bestsort/article/details/80796531?spm=1001.2014.3001.5506

K. 【模板】逆序对统计

题目描述

给定一个整数序列a1,a2,…,ana1,a2,…,an,如果存在i<ji<j 并且ai>ajai>aj,那么我们称之为逆序对。

求逆序对的数目

输入格式

第一行为n,表示序列长度;

接下来的n行,第i+1行表示序列中的第i个数。

输出格式

所有逆序对总数.

样例数据

input

4
3
2
3
2

output

3

L. 楼兰图腾

Description

在完成了分配任务之后,西部314来到了楼兰古城的西部。相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(‘V’),一个部落崇拜铁锹(‘∧’),他们分别用V和∧的形状来代表各自部落的图腾。

西部314在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了N个点,经测量发现这N个点的水平位置和竖直位置是两两不同的。西部314认为这幅壁画所包含的信息与这N个点的相对位置有关,因此不妨设坐标分别为(1,y1),(2,y2),…,(n,yn),其中y1~yn是1到n的一个排列。

西部314打算研究这幅壁画中包含着多少个图腾,其中V图腾的定义如下(注意:图腾的形式只和这三个纵坐标的相对大小排列顺序有关)1 <= i < j < k <= n且yi > yj,yj < yk;

而崇拜∧的部落的图腾被定义为1 <= i < j < k <= n且yi < yj , yj > yk;

西部314想知道,这n个点中两个部落图腾的数目。因此,你需要编写一个程序来求出V的个数和∧的个数。

= = = 精简版说明:

平面上有 N(N≤10^5 ) 个点,每个点的横、纵坐标的范围都是 1~N,任意两个点的横、纵坐标都不相同。

若三个点 (x1,y1),(x2,y2),(x3,y3)(x1,y1),(x2,y2),(x3,y3) 满足 x1<x2<x3,y1>y2x1<x2<x3,y1>y2 并且 y3>y2y3>y2,则称这三个点构成"v"字图腾。

若三个点 (x1,y1),(x2,y2),(x3,y3)(x1,y1),(x2,y2),(x3,y3) 满足 x1<x2<x3,y1<y2x1<x2<x3,y1<y2 并且 y3<y2y3<y2,则称这三个点构成"^"字图腾。

求平面上"v"和"^"字图腾的个数。

Input Format

第一行一个数n

第二行是n个数,分别代表y1,y2……yn

Output Format

两个数

中间用空格隔开

依次为V的个数和∧的个数

Sample Input

5
1 5 3 2 4

Sample Output

3 4

和之前一个题一样,用书写

M. 区间修改单点查询

题目描述

已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数数加上x

2.求出某一个数的值

输入格式

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含2或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k;

操作2: 格式:2 x 含义:输出第x个数的值。

输出格式

输出包含若干行整数,即为所有操作2的结果。

样例数据

input

5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4

output

6
10

N. Lost Cows

题目描述

FJFJ有nn头奶牛nleq100000nleq100000。已知它们的身高为1到n1到n各不相同,但是不知道每头奶牛的具体身高。

FJFJ带领着nn头奶牛去犬国进行友好的会晤。

现在到了晚餐时间,nn头奶牛排成一排出发去犬国第一大酒店用餐。FJFJ跟奶牛们强调了很多遍,要从矮到高排以彰显奶牛的风采;但是奶牛们并不听话。

FJFJ决定自己动手来给它们按身高排序。

但是FJFJ又没有犬国那么高的智商,所以它并没有记录下每一个位置的奶牛的身高。他只记录下了对于每一个位置的奶牛,排在它前面并且身高比它矮的奶牛的数量。

他不想在强大的犬国面前丢脸,所以找到了你。你需要告诉他排在每一个位置的牛的身高。

输入格式

第1行:单个整数,nn

第2行到第nn行:每行一个整数,描述了第11个位置到第i−1i−1个位置的奶牛,有多少头奶牛是比第ii头奶牛矮的。

(注:因为第一头牛前面没有牛,所以没有给出第一头牛前面的牛的个数)

输出格式

第1..n1..n行:每行一个整数,第ii行描述排在第ii个位置的奶牛的身高。

样例数据

input

5
1
2
1
0

output

2
4
5
3
1

O. [SHOI2007]园丁的烦恼

题目背景

很久很久以前,在遥远的大陆上有一个美丽的国家。统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草。

有一天国王漫步在花园里,若有所思,他问一个园丁道: “最近我在思索一个问题,如果我们把花坛摆成六个六角形,那么……”

“那么本质上它是一个深度优先搜索,陛下。”园丁深深地向国王鞠了一躬。

“嗯……我听说有一种怪物叫九头蛇,它非常贪吃苹果树……”

“是的,显然这是一道经典的动态规划题,早在 N 元 40024002 年我们就已经发现了其中的奥秘了,陛下。”

“该死的,你究竟是什么来头?”

“陛下息怒,干我们的这行经常莫名其妙地被问到和 OI 有关的题目,我也是为了预防万一啊!” 王者的尊严受到了伤害,这是不可容忍的。

题目描述

看来一般的难题是难不倒这位园丁的,国王最后打算用车轮战来消耗他的实力: “年轻人,在我的花园里有 nn 棵树,每一棵树可以用一个整数坐标来表示,一会儿,我的 mm 个骑士们会来轮番询问你某一个矩阵内有多少树,如果你不能立即答对,你就准备走人吧!”说完,国王气呼呼地先走了。

这下轮到园丁傻眼了,他没有准备过这样的问题。所幸的是,作为“全国园丁保护联盟”的会长——你,可以成为他的最后一根救命稻草。

输入格式

第一行有两个整数 n,mn,m,分别表示树木个数和询问次数。

接下来 nn 行,每行两个整数 x,yx,y,表示存在一棵坐标为 (x,y)(x,y) 的树。有可能存在两棵树位于同一坐标。

接下来 mm 行,每行四个整数 a,b,c,da,b,c,d,表示查询以 (a,b)(a,b) 为左下角,(c,d)(c,d) 为右上角的矩形内部(包括边界)有多少棵树。

输出格式

对于每个查询,输出一行一个整数表示答案。

样例

输入样例1

3 1
0 0 
0 1
1 0
0 0 1 1

输出样例1

3

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值