欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

2019 Multi-University Training Contest 6 1005Snowy Smile —— 线段树

发布时间:2023/12/20 56 豆豆
生活随笔 收集整理的这篇文章主要介绍了 2019 Multi-University Training Contest 6 1005Snowy Smile —— 线段树 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

This way

题意:

空间中有n个点,让你选择一个矩形覆盖一些点或者不覆盖任何点使得这个矩形中所有点的和最大。

题解:

虽然貌似它是个2000*2000的矩阵,但是它有的点只有2000个。所以我们先按照x轴排序,然后枚举左端点的同时枚举右端点,意思是固定左右端点,一定包括这两个点的最大子矩阵是多少。用线段树维护区间前缀和,然后查上面的最大前缀和-下面的最小前缀和,就像下图:

但是有一个很重要的剪枝,也就是在每次查询之前看看mx[1]-max(0ll,mi[1])是否小于等于ans,如果是的话就没必要往下做了。虽然不严谨,但是对于答案是不会有影响的。

#include<bits/stdc++.h> //#pragma GCC optimize(2) using namespace std; #define ll long long const int N=2e3+5; const ll inf=1e18; int dis_x[N],dis_y[N]; ll mi[N*4],mx[N*4],flag[N*4],pre[N*4]; struct node {int x,y;ll w;bool operator< (const node& a)const{return x<a.x;} }p[N]; vector<node>have[N]; void push_down(int root) {if(flag[root]==inf)return ;mi[root<<1]+=flag[root];mi[root<<1|1]+=flag[root];mx[root<<1]+=flag[root];mx[root<<1|1]+=flag[root];flag[root<<1]+=flag[root];flag[root<<1|1]+=flag[root];flag[root]=0; } void update(int l,int r,int root,int ql,int qr,ll v) {if(l>=ql&&r<=qr){mi[root]+=v;mx[root]+=v;flag[root]+=v;return ;}push_down(root);int mid=l+r>>1;if(mid>=ql)update(l,mid,root<<1,ql,qr,v);if(mid<qr)update(mid+1,r,root<<1|1,ql,qr,v);mi[root]=min(mi[root<<1],mi[root<<1|1]);mx[root]=max(mx[root<<1],mx[root<<1|1]); } ll q_mi(int l,int r,int root,int ql,int qr) {if(l>=ql&&r<=qr)return mi[root];push_down(root);int mid=l+r>>1;ll ans=inf;if(mid>=ql)ans=q_mi(l,mid,root<<1,ql,qr);if(mid<qr)ans=min(ans,q_mi(mid+1,r,root<<1|1,ql,qr));return ans; } ll q_mx(int l,int r,int root,int ql,int qr) {if(l>=ql&&r<=qr)return mx[root];push_down(root);int mid=l+r>>1;ll ans=-inf;if(mid>=ql)ans=q_mx(l,mid,root<<1,ql,qr);if(mid<qr)ans=max(ans,q_mx(mid+1,r,root<<1|1,ql,qr));return ans; } int main() {int t;scanf("%d",&t);while(t--){int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d%d%lld",&p[i].x,&p[i].y,&p[i].w),dis_x[i]=p[i].x,dis_y[i]=p[i].y,have[i].clear();sort(dis_x+1,dis_x+1+n);sort(dis_y+1,dis_y+1+n);int all_x=unique(dis_x+1,dis_x+1+n)-dis_x-1;int all_y=unique(dis_y+1,dis_y+1+n)-dis_y-1;for(int i=1;i<=n;i++){p[i].x=lower_bound(dis_x+1,dis_x+1+all_x,p[i].x)-dis_x;p[i].y=lower_bound(dis_y+1,dis_y+1+all_y,p[i].y)-dis_y;have[p[i].x].push_back(p[i]);}sort(p+1,p+1+n);ll ans=0;for(int i=1;i<=n;i++){for(int j=0;j<=4*all_y;j++)mi[j]=0,mx[j]=0,flag[j]=0;for(int j=i;j<=n;j++){if(p[j].x==p[j-1].x&&p[j].y==p[j-1].y)continue;if(p[j].x!=p[j-1].x||j==i)for(auto v:have[p[j].x])update(1,all_y,1,v.y,all_y,v.w);q_mi(1,all_y,1,1,all_y);if(mx[1]-min(0ll,mi[1])<=ans)continue;int l=min(p[i].y,p[j].y),r=max(p[i].y,p[j].y);ll maxn=q_mx(1,all_y,1,r,all_y);ll minn=l-1>0?q_mi(1,all_y,1,1,l-1):0ll;if(minn<=0)ans=max(ans,maxn-minn);elseans=max(ans,maxn);}}printf("%lld\n",ans);}return 0; } /* 10 7 1 1 -1000000000 1 2 2000000000 1 3 3000000000 2 2 -2000000000 2 3 -2000000000 3 2 4000000000 3 3 5000000000 10 8 1 3 20 1 5 -30 1 7 10 5 5 60 5 2 -140 5 1 120 4 1 -130 2 8 -1118 1 3 40 1 5 -30 1 7 10 5 5 60 5 2 -140 5 1 120 4 1 -130 2 8 -111*/

总结

以上是生活随笔为你收集整理的2019 Multi-University Training Contest 6 1005Snowy Smile —— 线段树的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。