zoukankan      html  css  js  c++  java
  • CodeForces 516C Drazil and Park 线段树

    原文链接http://www.cnblogs.com/zhouzhendong/p/8990745.html

    题目传送门 - CodeForces 516C

    题意

      在一个环上,有$n$棵树。

      给出每一个树的高度$h_i$以及每一个树距离他顺时针方向后一个树的距离$d_i$。

      有$m$次询问,每次,都会有一段连续区间内的树萎掉。请你找两棵树$x,y$,最大化$2(h_x+h_y)+dist(x,y)$。其中$dist(x,y)$为这两棵树的距离,这个距离不能包含萎掉的树。

      $n,mleq 10^5$

    题解

      闭着眼睛都能想到线段树。

      我们首先闭着眼睛给$d_i$求个前缀和。

      然后开线段树,维护区间$2h_i-d_{i-1}$的最大值以及$2h_i+d_{i-1}$的最大值,以及区间匹配的两个树的最大的$2(h_x+h_y)+dist(x,y)$。

      然后倍长原序列,每次询问就是区间求$max$。

      UPD(发表这篇博文约30分钟后):

      代码重写了哈哈。又短又漂亮。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=200005;
    const LL INF=1LL<<56;
    int n,m;
    LL d[N],h[N];
    struct Segment{
    	LL val,v0,v1;
    	Segment(){}
    	Segment(LL a,LL b,LL c){
    		val=a,v0=b,v1=c;
    	}
    }t[N<<2];
    LL read(){
    	LL x=0;
    	char ch=getchar();
    	while (!('0'<=ch&&ch<='9'))
    		ch=getchar();
    	while ('0'<=ch&&ch<='9')
    		x=x*10+ch-48,ch=getchar();
    	return x;
    }
    Segment merge(Segment ls,Segment rs){
    	Segment rt;
    	rt.val=max(max(ls.val,rs.val),ls.v0+rs.v1);
    	rt.v0=max(ls.v0,rs.v0);
    	rt.v1=max(ls.v1,rs.v1);
    	return rt;
    }
    void build(int rt,int L,int R){
    	if (L==R){
    		t[rt].v0=h[L]-d[L-1],t[rt].v1=h[L]+d[L-1],t[rt].val=-INF;
    		return;
    	}
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,L,mid);
    	build(rs,mid+1,R);
    	t[rt]=merge(t[ls],t[rs]);
    }
    Segment query(int rt,int L,int R,int xL,int xR){
    	if (L>xR||R<xL||xL>xR)
    		return Segment(-INF,-INF,-INF);
    	if (xL<=L&&R<=xR)
    		return t[rt];
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	return merge(query(ls,L,mid,xL,xR),query(rs,mid+1,R,xL,xR));
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		d[i]=read()+d[i-1];
    	for (int i=1;i<=n;i++)
    		h[i]=read()*2;
    	for (int i=1;i<=n;i++)
    		d[i+n]=d[i]+d[n],h[i+n]=h[i];
    	build(1,1,n*2);
    	for (int i=1,a,b;i<=m;i++){
    		scanf("%d%d",&a,&b);
    		if (b>=a)
    			a+=n;
    		printf("%I64d
    ",query(1,1,n*2,b+1,a-1).val);
    	}
    	return 0;
    }
    

      

    题解 - 续 (修改前的题解后一半以及代码)

      然而我代码写的很

      首先,区间求$max$的时候因为懒,为了少写一点代码,强行把一个$log$的算法写成$log^2$的。

      第二,我线段树维护的前两个信息不是最大值,而是编号……于是自找麻烦。

      第三,我没有倍长……

      (有空重写)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=100005;
    int n,m;
    LL d[N],h[N],val[N<<2];
    int M[2][N<<2];
    LL read(){
    	LL x=0;
    	char ch=getchar();
    	while (!('0'<=ch&&ch<='9'))
    		ch=getchar();
    	while ('0'<=ch&&ch<='9')
    		x=x*10+ch-48,ch=getchar();
    	return x;
    }
    LL c(int t,int i){
    	if (i==0)
    		return -(1LL<<55);
    	return t==0?(h[i]-d[i-1]):(h[i]+d[i-1]);
    }
    int pushup(int ls,int rs,int t){
    	return c(t,ls)>c(t,rs)?ls:rs;
    }
    void build(int rt,int L,int R){
    	if (L==R){
    		M[0][rt]=M[1][rt]=L,val[rt]=-(1LL<<55);
    		return;
    	}
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,L,mid);
    	build(rs,mid+1,R);
    	M[0][rt]=pushup(M[0][ls],M[0][rs],0);
    	M[1][rt]=pushup(M[1][ls],M[1][rs],1);
    	val[rt]=max(max(val[ls],val[rs]),c(0,M[0][ls])+c(1,M[1][rs]));
    }
    int query(int rt,int L,int R,int xL,int xR,int t){
    	if (L>xR||R<xL||xL>xR)
    		return 0;
    	if (xL<=L&&R<=xR)
    		return M[t][rt];
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	return pushup(query(ls,L,mid,xL,xR,t),query(rs,mid+1,R,xL,xR,t),t);
    }
    LL query(int rt,int L,int R,int xL,int xR){
    	if (L>xR||R<xL||xL>xR)
    		return 0;
    	if (xL<=L&&R<=xR)
    		return val[rt];
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	return max(max(query(ls,L,mid,xL,xR),query(rs,mid+1,R,xL,xR)),c(0,query(ls,L,mid,xL,xR,0))+c(1,query(rs,mid+1,R,xL,xR,1)));
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		d[i]=read()+d[i-1];
    	for (int i=1;i<=n;i++)
    		h[i]=read()*2;
    	build(1,1,n);
    	for (int i=1,a,b;i<=m;i++){
    		scanf("%d%d",&a,&b);
    		if (b<a){
    			printf("%I64d
    ",query(1,1,n,b+1,a-1));
    		}
    		else {
    			LL ans=max(query(1,1,n,1,a-1),query(1,1,n,b+1,n));
    			ans=max(ans,c(1,query(1,1,n,1,a-1,1))+d[n]+c(0,query(1,1,n,b+1,n,0)));
    			printf("%I64d
    ",ans);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    vue生命周期总结
    Generator的基本用法
    React context基本用法
    盗链
    Linux 黑白界面显示
    nginx 反向代理Apache
    apache+php windows下配置
    正则表达式匹配空行
    列表页条目不刷新删除
    linux终端自定义设置
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF516C.html
Copyright © 2011-2022 走看看