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); }