维护直线的线段树:Bzoj1568,Bzoj3938(Uoj88)
有这样一类线段树,可以维护一些直线方程并对每个点求出最大值。
首先先看BZOJ1568,输入给你条直线的方程,你需要对于指定的位置求出最大的函数值。
看到数据范围nlog^2n可做,考虑用线段树去维护。对于每个区间,怎么维护这个区间最高的直线呢?
显然,对于这个区间而言,最高的直线在各个位置都可能是不同的,看起来不是很可做。但是,我们能对于每个长度为1的区间维护最高的直线。
然而这样需要把修改push到底,时间复杂度为线性,所以应该怎么办呢?
考虑标记永久化,对于每个区间,维护其中点最高的直线。然后查询时对于跨越的多个区间的答案取max,这样可以完成查询。
怎么修改呢?考虑在某个区间上有两条直线(一条原来的,一条新加的),如果一条在整个区间都在另一条之上,那么可以把下面的那条线扔掉,直接返回。否则把中点较高的那一条留在这个区间,另外一条向(这条线)比留下的更高的一个子区间下放。
考虑这样为什么是对的,因为如果一条线在中点比另一条高,那么在某一边区间这条线一定完全“碾压”另一条线,另外一条是没有用的。所以只把另外一条在另一个子区间下放即可(自己画图或脑补一下就明白了)。
这个东西的复杂度是log^2n,因为最多修改logn个区间,对于每个区间最多下放logn层。
然后问题就解决了。
上代码:
BZOJ1568:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=5e4+1e2; 8 9 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3]; 10 int mid[maxn<<3]; 11 double k[maxn<<3],b[maxn<<3]; 12 int n,m,cnt; 13 14 inline double f(const double &k,const double &b,const int &x) { 15 return k * ( x - 1 ) + b; 16 } 17 inline void build(int pos,int ll,int rr) { 18 l[pos] = ll , r[pos] = rr; 19 if( ll == rr ) 20 return; 21 mid[pos] = ( ll + rr ) >> 1; 22 build(lson[pos]=++cnt,ll,mid[pos]); 23 build(rson[pos]=++cnt,mid[pos]+1,rr); 24 } 25 inline void update(int pos,double kk,double bb) { 26 if( f(kk,bb,l[pos]) <= f(k[pos],b[pos],l[pos]) && f(kk,bb,r[pos]) <= f(k[pos],b[pos],r[pos]) ) 27 return; 28 if( l[pos] == r[pos] ) { 29 k[pos] = kk , b[pos] = bb; 30 return; 31 } 32 if( kk > k[pos] ) { 33 if( f(kk,bb,mid[pos]) > f(k[pos],b[pos],mid[pos]) ) { 34 update(lson[pos],k[pos],b[pos]); 35 k[pos] = kk , b[pos] = bb; 36 } 37 else 38 update(rson[pos],kk,bb); 39 } 40 else { 41 if( f(kk,bb,mid[pos]) > f(k[pos],b[pos],mid[pos]) ) { 42 update(rson[pos],k[pos],b[pos]); 43 k[pos] = kk , b[pos] = bb; 44 } 45 else 46 update(lson[pos],kk,bb); 47 } 48 } 49 inline double query(int pos,int tar) { 50 if( l[pos] == r[pos] ) 51 return f(k[pos],b[pos],tar); 52 if( tar <= mid[pos] ) 53 return max( f(k[pos],b[pos],tar) , query(lson[pos],tar) ); 54 else if( tar > mid[pos] ) 55 return max( f(k[pos],b[pos],tar) , query(rson[pos],tar) ); 56 } 57 58 int main() { 59 static char com[20]; 60 static double qq,kk,bb; 61 scanf("%d",&m) , n = 5e4; 62 build(cnt=1,1,n); 63 for(int i=1,p;i<=m;i++) { 64 scanf("%s",com); 65 if( *com == 'Q' ) { 66 scanf("%d",&p); 67 qq = query(1,p); 68 printf("%d\n",((int)qq)/100); 69 } 70 else { 71 scanf("%lf%lf",&bb,&kk); 72 update(1,kk,bb); 73 } 74 } 75 return 0; 76 }
UOJ88:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cctype> 6 #define lli long long int 7 #define debug cout 8 using namespace std; 9 const int maxn=1e5+1e2,maxq=6e5+1e2; 10 11 lli srt[maxq]; 12 13 inline lli f(const lli &k,const lli &b,const int &x) { 14 return k * srt[x] + b; 15 } 16 17 int lson[maxq<<3],rson[maxq<<3]; 18 struct SegmentTree { 19 int cnt; 20 lli k[maxq<<3],b[maxq<<3]; 21 22 inline void build(int pos,int ll,int rr) { 23 if( ll == rr ) 24 return; 25 const int mid = ( ll + rr ) >> 1; 26 build(lson[pos]=++cnt,ll,mid); 27 build(rson[pos]=++cnt,mid+1,rr); 28 } 29 inline void update(int pos,int l,int r,int ll,int rr,lli kk,lli bb) { 30 if( rr < l || r < ll ) 31 return; 32 const int mid = ( l + r ) >> 1; 33 if( ll <= l && r <= rr ) { 34 if( f(kk,bb,l) <= f(k[pos],b[pos],l) && f(kk,bb,r) <= f(k[pos],b[pos],r) ) 35 return; 36 if( l == r ) { 37 k[pos] = kk , b[pos] = bb; 38 return; 39 } 40 if( kk > k[pos] ) { 41 if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) { 42 update(lson[pos],l,mid,l,r,k[pos],b[pos]); 43 k[pos] = kk , b[pos] = bb; 44 } 45 else 46 update(rson[pos],mid+1,r,ll,rr,kk,bb); 47 } 48 else { 49 if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) { 50 update(rson[pos],mid+1,r,l,r,k[pos],b[pos]); 51 k[pos] = kk , b[pos] = bb; 52 } 53 else 54 update(lson[pos],l,mid,ll,rr,kk,bb); 55 } 56 } 57 update(lson[pos],l,mid,ll,rr,kk,bb); 58 update(rson[pos],mid+1,r,ll,rr,kk,bb); 59 } 60 inline lli query(int pos,int l,int r,int tar) { 61 lli ret = f(k[pos],b[pos],tar); 62 if( l == r ) 63 return ret; 64 const int mid = ( l + r ) >> 1; 65 if( tar <= mid ) 66 ret = max( ret , query(lson[pos],l,mid,tar) ); 67 else 68 ret = max( ret , query(rson[pos],mid+1,r,tar) ); 69 return ret; 70 } 71 }up,down; 72 73 int s[maxn],st[maxq],ed[maxq]; 74 lli k[maxq],b[maxq]; 75 int ope[maxq][4]; 76 int n,m,len=1,cnt; 77 int v[maxn]; 78 79 inline lli getb(int pos,int tme,lli newk) { 80 lli alpha = f(k[pos],b[pos],tme); 81 return alpha - newk * srt[tme]; 82 } 83 inline void add(int pos,int tt,lli kk,lli bb=0) { 84 k[++cnt] = kk; 85 if( !bb ) 86 bb = getb(s[pos],tt,kk); 87 b[cnt] = bb; 88 st[cnt] = tt , ed[cnt] = len; 89 if( s[pos] ) 90 ed[s[pos]] = tt; 91 s[pos] = cnt; 92 } 93 94 inline void init() { 95 sort(srt+1,srt+1+len); 96 len = unique(srt+1,srt+1+len) - srt - 1; 97 for(int i=1;i<=m;i++) 98 ope[i][1] = lower_bound(srt+1,srt+1+len,ope[i][1]) - srt; 99 for(int i=1;i<=n;i++) 100 add(i,0,0,v[i]); 101 for(int i=1;i<=m;i++) 102 if( *ope[i] ) { 103 add(ope[i][2],ope[i][1],ope[i][3]); 104 } 105 106 up.build(up.cnt=1,1,len); 107 108 for(int i=1;i<=cnt;i++) { 109 up.update(1,1,len,st[i],ed[i],k[i],b[i]); 110 down.update(1,1,len,st[i],ed[i],-k[i],-b[i]); 111 } 112 } 113 114 inline void work() { 115 static lli ans; 116 for(int i=1;i<=m;i++) 117 if( ! *ope[i] ) { 118 ans = max( up.query(1,1,len,ope[i][1]) , down.query(1,1,len,ope[i][1]) ); 119 printf("%lld\n",ans); 120 } 121 } 122 123 int main() { 124 static char com[20]; 125 scanf("%d%d",&n,&m); 126 for(int i=1;i<=n;i++) 127 scanf("%d",v+i); 128 for(int i=1;i<=m;i++) { 129 scanf("%d",&ope[i][1]); 130 srt[++len] = ope[i][1]; 131 scanf("%s",com); 132 if( *com == 'c' ) { 133 ope[i][0] = 1; 134 scanf("%d%d",&ope[i][2],&ope[i][3]); 135 } 136 } 137 init(); 138 work(); 139 140 return 0; 141 }
上面的代码是无法通过BZOJ3938的,因为少了一个return。
BZOJ3938:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cctype> 6 #define lli long long int 7 #define debug cout 8 using namespace std; 9 const int maxn=1e5+1e2,maxq=6e5+1e2; 10 11 lli srt[maxq]; 12 13 inline lli f(const lli &k,const lli &b,const int &x) { 14 return k * srt[x] + b; 15 } 16 17 int lson[maxq<<3],rson[maxq<<3]; 18 struct SegmentTree { 19 int cnt; 20 lli k[maxq<<3],b[maxq<<3]; 21 22 inline void build(int pos,int ll,int rr) { 23 if( ll == rr ) 24 return; 25 const int mid = ( ll + rr ) >> 1; 26 build(lson[pos]=++cnt,ll,mid); 27 build(rson[pos]=++cnt,mid+1,rr); 28 } 29 inline void update(int pos,int l,int r,int ll,int rr,lli kk,lli bb) { 30 if( rr < l || r < ll ) 31 return; 32 const int mid = ( l + r ) >> 1; 33 if( ll <= l && r <= rr ) { 34 if( f(kk,bb,l) <= f(k[pos],b[pos],l) && f(kk,bb,r) <= f(k[pos],b[pos],r) ) 35 return; 36 if( l == r ) { 37 k[pos] = kk , b[pos] = bb; 38 return; 39 } 40 if( kk > k[pos] ) { 41 if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) { 42 update(lson[pos],l,mid,l,r,k[pos],b[pos]); 43 k[pos] = kk , b[pos] = bb; 44 } 45 else 46 update(rson[pos],mid+1,r,ll,rr,kk,bb); 47 } 48 else { 49 if( f(kk,bb,mid) > f(k[pos],b[pos],mid) ) { 50 update(rson[pos],mid+1,r,l,r,k[pos],b[pos]); 51 k[pos] = kk , b[pos] = bb; 52 } 53 else 54 update(lson[pos],l,mid,ll,rr,kk,bb); 55 } 56 return; 57 } 58 update(lson[pos],l,mid,ll,rr,kk,bb); 59 update(rson[pos],mid+1,r,ll,rr,kk,bb); 60 } 61 inline lli query(int pos,int l,int r,int tar) { 62 lli ret = f(k[pos],b[pos],tar); 63 if( l == r ) 64 return ret; 65 const int mid = ( l + r ) >> 1; 66 if( tar <= mid ) 67 ret = max( ret , query(lson[pos],l,mid,tar) ); 68 else 69 ret = max( ret , query(rson[pos],mid+1,r,tar) ); 70 return ret; 71 } 72 }up,down; 73 74 int s[maxn],st[maxq],ed[maxq]; 75 lli k[maxq],b[maxq]; 76 int ope[maxq][4]; 77 int n,m,len=1,cnt; 78 int v[maxn]; 79 80 inline lli getb(int pos,int tme,lli newk) { 81 lli alpha = f(k[pos],b[pos],tme); 82 return alpha - newk * srt[tme]; 83 } 84 inline void add(int pos,int tt,lli kk,lli bb=0) { 85 k[++cnt] = kk; 86 if( !bb ) 87 bb = getb(s[pos],tt,kk); 88 b[cnt] = bb; 89 st[cnt] = tt , ed[cnt] = len; 90 if( s[pos] ) 91 ed[s[pos]] = tt; 92 s[pos] = cnt; 93 } 94 95 inline void init() { 96 sort(srt+1,srt+1+len); 97 len = unique(srt+1,srt+1+len) - srt - 1; 98 for(int i=1;i<=m;i++) 99 ope[i][1] = lower_bound(srt+1,srt+1+len,ope[i][1]) - srt; 100 for(int i=1;i<=n;i++) 101 add(i,0,0,v[i]); 102 for(int i=1;i<=m;i++) 103 if( *ope[i] ) { 104 add(ope[i][2],ope[i][1],ope[i][3]); 105 } 106 107 up.build(up.cnt=1,1,len); 108 109 for(int i=1;i<=cnt;i++) { 110 up.update(1,1,len,st[i],ed[i],k[i],b[i]); 111 down.update(1,1,len,st[i],ed[i],-k[i],-b[i]); 112 } 113 } 114 115 inline void work() { 116 static lli ans; 117 for(int i=1;i<=m;i++) 118 if( ! *ope[i] ) { 119 ans = max( up.query(1,1,len,ope[i][1]) , down.query(1,1,len,ope[i][1]) ); 120 printf("%lld\n",ans); 121 } 122 } 123 124 inline int getint() { 125 int ret = 0 , fix = 1; 126 char ch = getchar(); 127 while( !isdigit(ch) ) 128 fix = ch == '-' ? -1 : fix, 129 ch = getchar(); 130 while( isdigit(ch) ) 131 ret = ret * 10 + ch - '0', 132 ch = getchar(); 133 return ret * fix; 134 } 135 int main() { 136 static char com[20]; 137 n = getint() , m = getint(); 138 for(int i=1;i<=n;i++) 139 v[i] = getint(); 140 for(int i=1;i<=m;i++) { 141 ope[i][1] = getint(); 142 srt[++len] = ope[i][1]; 143 scanf("%s",com); 144 if( *com == 'c' ) { 145 ope[i][0] = 1; 146 ope[i][2] = getint() , ope[i][3] = getint(); 147 } 148 } 149 init(); 150 work(); 151 152 return 0; 153 }
对了,今天我似乎达成成就:吓跑小学妹......话说我有那么凶神恶煞吗......