Educational Codeforces Round 73 (Rated for Div. 2)F(线段树,扫描线)

 这道题里线段树用来区间更新(每次给更大的区间加上当前区间的权重),用log的复杂度加快了更新速度,也用了区间查询(查询当前区间向右直至最右中以当前区间端点向右一段区间的和中最大的那一段的和),也用log的复杂度加快了查询速度。

  1 #define HAVE_STRUCT_TIMESPEC
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 int x[1000007],y[1000007];
  5 long long a[1000007];
  6 int cc[2000007];
  7 vector<pair<int,long long> >v[2000007];
  8 long long mx[4000007],lz[4000007],mxid[4000007];
  9 long long cmx,cid;
 10 int n,cnt;
 11 void up(int rt){
 12     if(mx[rt<<1]>=mx[rt<<1|1]){
 13         mx[rt]=mx[rt<<1];
 14         mxid[rt]=mxid[rt<<1];
 15     }
 16     else{
 17         mx[rt]=mx[rt<<1|1];
 18         mxid[rt]=mxid[rt<<1|1];
 19     }
 20 }
 21 void down(int rt){
 22     lz[rt<<1]+=lz[rt];
 23     lz[rt<<1|1]+=lz[rt];
 24     mx[rt<<1]+=lz[rt];
 25     mx[rt<<1|1]+=lz[rt];
 26     lz[rt]=0;
 27 }
 28 void build(int rt,int l,int r){
 29     if(l==r){
 30         mx[rt]=-cc[l];
 31         mxid[rt]=l;
 32         return ;
 33     }
 34     build(rt<<1,l,(l+r)>>1);
 35     build(rt<<1|1,((l+r)>>1)+1,r);
 36     up(rt);
 37 }
 38 void update(int rt,int l,int r,int L,int R,long long k){
 39     if(L<=l&&r<=R){
 40         lz[rt]+=k;
 41         mx[rt]+=k;
 42         return ;
 43     }
 44     down(rt);
 45     if(L<=((l+r)>>1))
 46         update(rt<<1,l,(l+r)>>1,L,R,k);
 47     if(R>((l+r)>>1))
 48         update(rt<<1|1,((l+r)>>1)+1,r,L,R,k);
 49     up(rt);
 50 }
 51 void query(int rt,int l,int r,int L,int R){
 52     if(L<=l&&r<=R){
 53         if(mx[rt]>cmx){
 54             cmx=mx[rt];
 55             cid=mxid[rt];
 56         }
 57         return ;
 58     }
 59     down(rt);
 60     if(L<=((l+r)>>1))
 61         query(rt<<1,l,(l+r)>>1,L,R);
 62     if(R>((l+r)>>1))
 63         query(rt<<1|1,((l+r)>>1)+1,r,L,R);
 64 }
 65 int main(){
 66     ios::sync_with_stdio(false);
 67     cin.tie(NULL);
 68     cout.tie(NULL);
 69     cnt=0;
 70     cin>>n;
 71     for(int i=1;i<=n;++i){
 72         cin>>x[i]>>y[i]>>a[i];
 73         cc[++cnt]=x[i];
 74         cc[++cnt]=y[i];
 75     }
 76     sort(cc+1,cc+1+cnt);
 77     cnt=unique(cc+1,cc+1+cnt)-(cc+1);//去重
 78     for(int i=1;i<=n;++i){
 79         x[i]=lower_bound(cc+1,cc+1+cnt,x[i])-cc;//离散化后的区间标号,不是坐标标号
 80         y[i]=lower_bound(cc+1,cc+1+cnt,y[i])-cc;//离散化后的区间标号
 81         if(x[i]>y[i])
 82             swap(x[i],y[i]);
 83         v[x[i]].push_back({y[i],a[i]});
 84     }
 85     long long ans=0;
 86     int cx=cc[cnt]+1;
 87     int cy=cx;
 88     build(1,1,cnt);
 89     //相当于把点坐标按照它们的纵坐标全部投影在y=x这条线上,同时为了使枚举复杂度降低,利用相对位置代替坐标,这里的数组下标指的是第几个区间,而不是第几个单位长度
 90     for(int i=cnt;i;--i){//固定正方形的左下端点所在区间端点,每次选取从当前区间端点向右的连续的一段区间作为当前区间最大值的所在区间
 91         for(int j=0;j<v[i].size();++j){
 92             int r=v[i][j].first;//纵轴上的区间端点
 93             long long w=v[i][j].second;
 94             update(1,1,cnt,r,cnt,w);//更新当前纵轴上区间端点右边区间的值,如果右边区间被选中的话,它左边区间里的点都会被选中,所以更新更右侧的区间最大值
 95         }
 96         cmx=-2e18;
 97         cid=-1;
 98         query(1,1,cnt,i,cnt);//查询区间最大值,即查询是否有区间【i,j】这一段区间内的点的和减去j这个区间端点(相对位置)的纵坐标是至今为止最大的,有的话就更新最大值和此时的横纵坐标
 99         if(ans<cmx+cc[i]){
100             ans=cmx+cc[i];//新的最大值
101             cx=cc[i];//此时的横坐标
102             cy=cc[cid];//此时的纵坐标
103         }
104     }
105     cout<<ans<<"\n";
106     cout<<cx<<" "<<cx<<" "<<cy<<" "<<cy;
107     return 0;
108 }
posted @ 2019-09-28 08:26  sewage  阅读(201)  评论(0编辑  收藏  举报