hihoCoder挑战赛20解题报告

题目1 : 打折机票

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

hihoCoder挑战赛20解题报告_第1张图片

 因为思念新宿的"小姐姐"们,岛娘计划6月份再去一趟东京,不过这次看来她需要自掏腰包。经过了几天的夜战,岛娘终于在体力耗尽之前,用Python抓下了所有6月份,上海至东京的全部共 n 张机票。现在请你帮助债台高筑的岛娘筛选出符合时间区间要求的,最贵的机票。

输入

输入数据的第一行包含两个整数 n, m(1 ≤ n, m ≤ 105),分别表示机票的总数,和询问的总数。接下来的 n 行,每行两个整数 t, v (1 ≤ t, v ≤ 105),表示每张机票出发的时间和价格。 接下来的 m 行,每行两个整数 a, b (1 ≤ a ≤ b ≤ 105),表示每个询问所要求的时间区间。

输出

对于每组询问,输出一行表示最贵的价格。如果没有符合要求的机票,输出一行"None"。

样例输入
7 6
1 1
2 1
4 3
4 4
4 5
6 9
7 9
1 7
1 2
6 7
3 3
4 4
5 5
样例输出
9
1
9
None
5
None
解题思路:纯线段树模板题,求区间最大值

题目链接→1299 打折机票

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-4
using namespace std;
const int N = 100005;
const int M = 100000;
const int inf = 100000;
const int mod = 2009;
struct tree
{
    int left,right,Max;
}s[4*N];
int a[N];
void buildtree(int l,int r,int p)
{
    s[p].left=l,s[p].right=r;
    if(l==r)
    {
        s[p].Max=a[l];
        return ;
    }
    int mid=(l+r)/2;
    buildtree(l,mid,p*2);
    buildtree(mid+1,r,p*2+1);
    s[p].Max=max(s[p*2].Max,s[p*2+1].Max);
}
int search(int l,int r,int p)
{
    if(l<=s[p].left&&s[p].right<=r)
        return s[p].Max;
    int mid=(s[p].left+s[p].right)/2;
    if(l>mid)
        return search(l,r,p*2+1);
    else if(r<=mid)
        return search(l,r,p*2);
    else
        return max(search(l,mid,p*2),search(mid+1,r,p*2+1));

}
int main()
{
    int n,m,i,t,v,l,r,ans;
    while(~scanf("%d%d",&n,&m))
    {
    	memset(a,0,sizeof(a));
    	for(i=1;i<=n;i++)
   		{
		   	scanf("%d%d",&t,&v);
		   	a[t]=max(a[t],v);
	   	}
	   	buildtree(1,n,1);
    	for(i=0;i<m;i++)
    	{
        	scanf("%d%d",&l,&r);
        	ans=search(l,r,1);
        	if(!ans)
        		puts("None");
       		else
	        	printf("%d\n",ans);
    	}
    }
    return 0;
}

题目2 : 展胜地的鲤鱼旗

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

岩手县北上市的「北上市立公园展胜地」,是陆奥国三大樱花名所之一。每年的四月中旬到五月初,这里都会举办盛大的祭奠。除了可以在盛开的樱花步道上乘坐观光马车徐行、还有横跨北上川上的鲤鱼旗,河畔还有当地特有的为祭奠祖先而编创的北上鬼剑舞。

hihoCoder挑战赛20解题报告_第2张图片

假设,我们用一个包含 '(', ')'的括号字符串来区别每面鲤鱼旗的方向。一段括号序列被称为合法的,当且仅当满足两个条件:一、对于整个序列,左括号数量等于右括号;二、对于任意前缀,左括号的数目都不小于右括号的数目。岛娘想知道,对于一串括号字符串,有多少子串是合法的,你能帮助她么。

输入

输入数据仅一行,包含一个长度为 n (1 ≤ n ≤ 106) 的括号字符串。

输出

输出一行,表示合法的括号子串的数目。

样例输入
(()())
样例输出
4
解题思路:括号匹配问题,不过找的是合法的子串数目

首先,我们来整理一下如何求合法的子串数目

对于(()()(()))(),其实可以把各种括号进行分层

(( ) ( )(( ))) ( )

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

相同层的用等差数列求和就能算得当层的合法子串数

而需要特别处理的是多余的右括号,即没有左括号能与之匹配的右括号,对于这些右括号,统一分成-1组,不对其做处理即可

如:

 )  )  )  ) ( ( ) ( ) )

-1 -1 -1 -1 0 1 1 1 1 0

题目链接→1300 展胜地的鲤鱼旗

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-4
using namespace std;
const int N = 1000005;
const int M = 100000;
const int inf = 100000;
const int mod = 2009;
char s[N];
stack<char> p;
stack<int> m;
int ans[N],q[N];
int main()
{
    int i,k,c;
    while(~scanf("%s",s))
    {
    	c=k=0;
    	while(!p.empty())
			p.pop();
		while(!m.empty())
			m.pop();
		for(i=0;s[i]!='\0';i++)
			if(s[i]=='(')
			{
				if(m.empty())
					m.push(0);
				else
					m.push(m.top()+1);
				q[k++]=m.top();
				p.push('(');
			}
			else
			{
				if(!p.empty()&&p.top()=='(')
				{
					q[k++]=m.top();
					p.pop();
					m.pop();
				}
				else
				{
					p.push(')');
					q[k++]=-1;
				}
			}
		/*for(i=0;i<k;i++)
			printf("%d ",q[i]);
		puts("");*/
		memset(ans,0,sizeof(ans));
		ans[q[0]]++;
		for(i=1;i<k;i++)
		{
			if(q[i]<q[i-1])
			{
				if(q[i-1]!=-1)
				{
					ans[q[i-1]]/=2;
					c+=ans[q[i-1]]*(ans[q[i-1]]+1)/2;
					ans[q[i-1]]=0;
				}	
			}
			ans[q[i]]++;
			//printf("%d %d\n",i,c);
		}
		if(q[i-1]!=-1)
		{
			ans[q[i-1]]/=2;
			c+=ans[q[i-1]]*(ans[q[i-1]]+1)/2;
			ans[q[i-1]]=0;
			//printf("#c=%d\n",c);
		}
		for(i=q[i-1]-1;i>=0;i--)
		{
			ans[i]/=2;
			c+=ans[i]*(ans[i]+1)/2;
			ans[i]=0;
			//printf("@c=%d\n",c);
		}
		printf("%d\n",c);
    }	
    return 0;
}
/*
()()(())())
(())()))(((()))(()
*/

菜鸟成长记

你可能感兴趣的:(线段树,ACM)