bzoj1537 [POI2005]Aut- The Bus

Description

Byte City 的街道形成了一个标准的棋盘网络 – 他们要么是北南走向要么就是西东走向. 北南走向的路口从 1 到 n编号, 西东走向的路从1 到 m编号. 每个路口用两个数(i, j) 表示(1 <= i <= n, 1 <= j <= m). Byte City里有一条公交线, 在某一些路口设置了公交站点. 公交车从 (1, 1) 发车, 在(n, m)结束.公交车只能往北或往东走. 现在有一些乘客在某些站点等车. 公交车司机希望在路线中能接到尽量多的乘客.帮他想想怎么才能接到最多的乘客.

Input

第一行三个数n, m 和 k – 表示北南走向的路的个数以及西东走向的路和乘客等车的站点的个数. ( 1 <= n <= 10^9, 1 <= m <= 10^9, 1 <= k <= 10^5). 接下来k 行每行描述一个公交站的信息.第 i + 1 行三个正整数 xi, yi 和 pi, 1 <= xi <= n, 1 <= yi <= m, 1 <= pi <= 10^6. 表示在(xi, yi) 有 pi 个乘客在等车. 每个路口在数据中最多出现一次,乘客总数不会超过1 000 000 000.

Output

一个数表示最多能接到的乘客数量.

Sample Input

8 7 11
4 3 4
6 2 4
2 3 2
5 6 1
2 5 2
1 5 5
2 1 1
3 1 1
7 7 1
7 4 2
8 6 2

Sample Output

11

题意是按xy坐标均递增的顺序取点,使得点权和最大

先把x坐标排序,然后按顺序取点就可以保证x坐标递增

然后是考虑y坐标大小的关系

设f[i]表示排序完取到前i个点,且第i个点被取到的最大价值

假设当前取了第i个点,那么上一个取的第j个点必须满足j<i,y[j]<y[i],方程是f[i]=max(f[j]+v[i])

于是我们把y坐标离散掉,用一个随便什么数据结构维护,a[k]为所有y[j]=k的点的最大f[j],每次查询1到y[i]的最大值作为f[j]更新就好了

写了两种:树状数组和线段树,事实证明树状数组比线段树常数小了好多啊

逗比了一下直接输出了f[k],所以wa两次……显然应该输出max(f[i])啊为什么我这么sb

下面是线段树代码(604ms):

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 0x7ffffff
#define pa pair<int,int>
#define pi 3.1415926535897932384626433832795028841971
using namespace std;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
struct ydat{int d,rnk;}yy[100010];bool operator<(ydat a,ydat b){return a.d<b.d;}
struct peo{int x,y,z;}p[100010];bool operator<(peo a,peo b){return a.x<b.x||a.x==b.x&&a.y<b.y;}
struct segtree{int l,r,mx;}tree[500010];
int n,m,k,cnt,mx;
int f[100010];
inline void update(int k)
{tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx);}
inline void buildtree(int now,int l,int r)
{
	tree[now].l=l;tree[now].r=r;
	if (l==r)return;
	int mid=(l+r)>>1;
	buildtree(now<<1,l,mid);
	buildtree(now<<1|1,mid+1,r);
}
inline int ask(int now,int x,int y)
{
	int l=tree[now].l,r=tree[now].r;
	if (l==x&&y==r)return tree[now].mx;
	int mid=(l+r)>>1;
	if (mid>=y)return ask(now<<1,x,y);
	else if (x>mid)return ask(now<<1|1,x,y);
	else return max(ask(now<<1,x,mid),ask(now<<1|1,mid+1,y));
}
inline void add(int now,int x,int dat)
{
	int l=tree[now].l,r=tree[now].r;
	if (l==r)
	{
		tree[now].mx=max(tree[now].mx,dat);
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)add(now<<1,x,dat);
	else add(now<<1|1,x,dat);
	update(now);
}
int main()
{

	n=read();m=read();k=read();
	for(int i=1;i<=k;i++)
	{
		p[i].x=read();p[i].y=yy[i].d=read();p[i].z=read();
		yy[i].rnk=i;
	}
	sort(yy+1,yy+k+1);
	yy[0].d=-1;
	for (int i=1;i<=k;i++)
	{
		if (yy[i].d!=yy[i-1].d)cnt++;
		p[yy[i].rnk].y=cnt;
	}
	sort(p+1,p+k+1);
	buildtree(1,1,cnt);
	for (int i=1;i<=k;i++)
	{
		f[i]=p[i].z+ask(1,1,p[i].y);
		add(1,p[i].y,f[i]);
		mx=max(mx,f[i]);
	}
	printf("%d\n",mx);
}

然后是树状数组代码(344ms):

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 0x7ffffff
#define pa pair<int,int>
#define pi 3.1415926535897932384626433832795028841971
using namespace std;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
struct ydat{int d,rnk;}yy[100010];bool operator<(ydat a,ydat b){return a.d<b.d;}
struct peo{int x,y,z;}p[100010];bool operator<(peo a,peo b){return a.x<b.x||a.x==b.x&&a.y<b.y;}
int c[100010];
int n,m,k,cnt,mx;
int f[100010];
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int d)
{
    for (int i=x;i<=cnt;i+=lowbit(i))
      c[i]=max(c[i],d);
}
inline int ask(int x)
{
    int s=0;
    for (int i=x;i;i-=lowbit(i))
        s=max(s,c[i]);
    return s;
}
int main()
{

    n=read();m=read();k=read();
    for(int i=1;i<=k;i++)
    {
        p[i].x=read();p[i].y=yy[i].d=read();p[i].z=read();
        yy[i].rnk=i;
    }
    sort(yy+1,yy+k+1);
    yy[0].d=-1;
    for (int i=1;i<=k;i++)
    {
        if (yy[i].d!=yy[i-1].d)cnt++;
        p[yy[i].rnk].y=cnt;
    }
    sort(p+1,p+k+1);
    for (int i=1;i<=k;i++)
    {
        f[i]=p[i].z+ask(p[i].y);
        add(p[i].y,f[i]);
        mx=max(mx,f[i]);
    }
    printf("%d\n",mx);
}

最后我把树状数组的代码卡常数卡到了不能看的地步,居然卡到了308ms提交排名的rank1

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
struct ydat{int d,rnk;}yy[100010];
inline bool operator<(const ydat &a,const ydat &b){return a.d<b.d;}
struct peo{int x,y,z;}p[100010];
inline bool operator<(const peo &a,const peo &b){return a.x<b.x||a.x==b.x&&a.y<b.y;}
inline int max(const int &a,const int &b){return a>b?a:b;}
int c[100010];
int n,m,k,cnt,mx,now;
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int d)
{
    for (int i=x;i<=cnt;i+=lowbit(i))
      c[i]=max(c[i],d);
}
inline int ask(int x)
{
    int s=0;
    for (int i=x;i;i-=lowbit(i))
        s=max(s,c[i]);
    return s;
}
int main()
{

    n=read();m=read();k=read();
    for(int i=1;i<=k;i++)
    {
        p[i].x=read();yy[i].d=read();p[i].z=read();
        yy[i].rnk=i;
    }
    sort(yy+1,yy+k+1);
    yy[0].d=-1;
    for (int i=1;i<=k;i++)
    {
        if (yy[i].d!=yy[i-1].d)cnt++;
        p[yy[i].rnk].y=cnt;
    }
    sort(p+1,p+k+1);
    for (int i=1;i<=k;i++)
    {
        now=p[i].z+ask(p[i].y);
        add(p[i].y,now);
        mx=max(mx,now);
    }
    printf("%d\n",mx);
}
时间: 2024-11-09 23:06:04

bzoj1537 [POI2005]Aut- The Bus的相关文章

BZOJ 1537: [POI2005]Aut- The Bus(dp + BIT)

对y坐标离散化, 然后按x坐标排序, dp. 一个点(x, y), 设到达这个点接到的最多乘客数为t, 那么t可以用来更新y'>=y的所有点.用树状数组维护最大值. --------------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int maxn = 100009; int N; #def

Bzoj 1537: [POI2005]Aut- The Bus 题解 [由暴力到正解]

1537: [POI2005]Aut- The Bus Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 387  Solved: 264[Submit][Status][Discuss] Description Byte City 的街道形成了一个标准的棋盘网络 – 他们要么是北南走向要么就是西东走向. 北南走向的路口从 1 到 n编号, 西东走向的路从1 到 m编号. 每个路口用两个数(i, j) 表示(1 <= i <= n, 1 <= j

【BZOJ】1537: [POI2005]Aut- The Bus

[算法]DP+线段树求区间max(二维偏序) [题解] 状态转移方程:f[i]=max(f[j]+v[i]),x[j]<x[i]&&y[j]<y[i]. 观察j的条件限制显然是二维偏序求最大值,套路化地离散化后一维排序+一维线段树即可解决. 最后在f[i]中找max,所以不用恢复原序. 复杂度O(n log n). #include<cstdio> #include<cstring> #include<cctype> #include<

Bus System 【dijkstra算法】

Because of the huge population of China, public transportation is very important. Bus is an important transportation method in traditional public transportation system. And it's still playing an important role even now.The bus system of City X is qui

hdu 5163 Taking Bus(模拟)

hdu 5163 Taking Bus 问题描述 Bestland有一条非常长的马路,马路上设有n个公交汽车站.公交汽车站从左到右标号为1到n.有m个人想要乘公交.你的任务是找出每个人到终点为止所需要的时间.注意:你需要用来解决这道题目的信息在Input里面,请仔细阅读. 输入描述 输入的第一行包含一个整数T (1≤T≤60),表示测试数据的组数.对于每组测试数据:第一行包含两个整数n和m (2≤n,m≤105),表示公交车站的数目和乘客的数目. 接下来一行包含n?1个整数, d1,d2,-,d

【BZOJ 1528】 1528: [POI2005]sam-Toy Cars (贪心+堆)

1528: [POI2005]sam-Toy Cars Description Jasio 是一个三岁的小男孩,他最喜欢玩玩具了,他有n 个不同的玩具,它们都被放在了很高的架子上所以Jasio 拿不到它们. 为了让他的房间有足够的空间,在任何时刻地板上都不会有超过k 个玩具. Jasio 在地板上玩玩具. Jasio'的妈妈则在房间里陪他的儿子. 当Jasio 想玩地板上的其他玩具时,他会自己去拿,如果他想玩的玩具在架子上,他的妈妈则会帮他去拿,当她拿玩具的时候,顺便也会将一个地板上的玩具放上架

Matlab中使用脚本和xml文件自动生成bus模块

帮一个老师写的小工具 在一个大工程中需要很多bus来组织信号,而为了规范接口,需要定义很多BusObject,用Matlab语言手写这些BusObject比较费工夫 所以用xml配置文件来写,也便于更改总线数据接口,然后使用matlab脚本来生成BusObject和Bus模块库 以下代码运行环境:WIN10+Matlab2015a 下面给出代码Matlab函数的代码: function xmlbuscreator(xmlfile) % XMLBUSCREATOR:从xml文件读取数据结构,并生成

General Problem Solving Techniques [Intermediate-1]~G - The Bus Driver Problem

In a city there are n bus drivers. Also there are n morning bus routes and n afternoon bus routes withvarious lengths. Each driver is assigned one morning route and one evening route. For any driver, ifhis total route length for a day exceeds d, he h

[POI2005]Kos-Dicing|二分|最大流

1532: [POI2005]Kos-Dicing Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1222  Solved: 387[Submit][Status][Discuss] Description Dicing 是一个两人玩的游戏,这个游戏在Byteotia非常流行. 甚至人们专门成立了这个游戏的一个俱乐部. 俱乐部的人时常在一起玩这个游戏然后评选出玩得最好的人.现在有一个非常不走运的家伙,他想成为那个玩的最好的人,他现在知道了所有比赛的安