维护直线的线段树: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 }
View Code

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 }
View Code

 上面的代码是无法通过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 }
View Code

 

对了,今天我似乎达成成就:吓跑小学妹......话说我有那么凶神恶煞吗......

posted @ 2017-12-28 21:08  Cmd2001  阅读(292)  评论(0编辑  收藏  举报