文章目录
- SP2940 UNTITLE1 - Untitled Problem II
- source
- solution
- code
- Balanced Lineup
- source
- code
- Count on a tree II
- [ioi2009]Regions
SP2940 UNTITLE1 - Untitled Problem II
source
solution
分块
si={si+k×(i−l+1)=si+k×i+k×(1−l)l≤i≤rsi+k×(r−l+1)r<is_i=\begin{cases} s_i+k\times (i-l+1)=s_i+k\times i+k\times (1-l)&&l\le i\le r\\ s_i+k\times (r-l+1)&&r<i \end{cases} si={si+k×(i−l+1)=si+k×i+k×(1−l)si+k×(r−l+1)l≤i≤rr<i
对于整块而言k×(1−l)k\times(1-l)k×(1−l)和k×(r−l+1)k\times (r-l+1)k×(r−l+1)都可以看作常数,用区间标记tag
记录,再单独记录一下k
ans=max{si+kblocki×i+tagblocki}l≤i≤rans=\max\bigg\{s_i+k_{block_i}\times i+tag_{block_i}\bigg\}\qquad l\le i\le r ans=max{si+kblocki×i+tagblocki}l≤i≤r
对于l,rl,rl,r在的散块,暴力下放标记到块区间内,然后暴力查询
对于整块,发现max
的方程类似dpdpdp斜率优化转移,维护块内的上凸壳,二分求解
-
假设块内i<ji<ji<j,且ansi<ansjans_i<ans_jansi<ansj
-
ansi=si+kblockpi+tagblockpans_i=s_i+k_{block_p}i+tag_{block_p} ansi=si+kblockpi+tagblockp
-
ansj=sj+kblockpj+tagblockpans_j=s_j+k_{block_p}j+tag_{block_p} ansj=sj+kblockpj+tagblockp
-
-
ansi<ansj⇔si+kblockpi<sj+kblockpj⇔si−sj<kblockp(j−i)⇒sj−sij−i>−kblockpans_i<ans_j\Leftrightarrow s_i+k_{block_p}i<s_j+k_{block_p}j\Leftrightarrow s_i-s_j<k_{block_p}(j-i)\\\Rightarrow \frac{s_j-s_i}{j-i}>-k_{block_p} ansi<ansj⇔si+kblockpi<sj+kblockpj⇔si−sj<kblockp(j−i)⇒j−isj−si>−kblockp
code
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define maxn 50005
#define maxB 255
int n, B;
int s[maxn], block[maxn];struct node {int l, r, tag, k, top;struct point {int x, y;point(){}point( int X, int Y ) { x = X, y = Y; }friend double slope( point s, point t ) { return 1.0 * ( s.y - t.y ) / ( s.x - t.x ); }}sta[maxB];void build_hall() {top = k = tag = 0;for( int i = l;i <= r;i ++ ) {point now( i, s[i] );while( top > 1 && slope( sta[top], now ) >= slope( sta[top - 1], now ) ) top --;sta[++ top] = now;}sta[top + 1] = point( r + 1, -1e18 );}int calc() {int l = 1, r = top, pos = 0;while( l <= r ) {int mid = ( l + r ) >> 1;if( slope( sta[mid + 1], sta[mid] ) > -k ) l = mid + 1;else r = mid - 1, pos = mid;}return tag + sta[pos].x * k + sta[pos].y;}void init( int L, int R ) { l = L, r = R, build_hall(); }void pushdown() { for( int i = l;i <= r;i ++ ) s[i] += tag + k * i; }}t[maxB];void modify( int l, int r, int k ) {for( int i = block[r] + 1;i <= block[n];i ++ )t[i].tag += ( r - l + 1 ) * k;if( block[l] == block[r] ) {t[block[l]].pushdown();for( int i = l;i <= r;i ++ )s[i] += ( i - l + 1 ) * k;for( int i = r + 1;i <= t[block[l]].r;i ++ )s[i] += ( r - l + 1 ) * k;t[block[l]].build_hall();}else {for( int i = block[l] + 1;i < block[r];i ++ ) t[i].k += k, t[i].tag -= ( l - 1 ) * k;t[block[l]].pushdown();t[block[r]].pushdown();for( int i = l;i <= t[block[l]].r;i ++ )s[i] += ( i - l + 1 ) * k;for( int i = t[block[r]].l;i < r;i ++ )s[i] += ( i - l + 1 ) * k;for( int i = r;i <= t[block[r]].r;i ++ ) s[i] += ( r - l + 1 ) * k;t[block[l]].build_hall();t[block[r]].build_hall();}
}int query( int l, int r ) {int ans = -1e18;if( block[l] == block[r] ) {t[block[l]].pushdown();for( int i = l;i <= r;i ++ )ans = max( ans, s[i] );t[block[l]].build_hall();}else {t[block[l]].pushdown();t[block[r]].pushdown();for( int i = l;i <= t[block[l]].r;i ++ ) ans = max( ans, s[i] );for( int i = t[block[r]].l;i <= r;i ++ ) ans = max( ans, s[i] );for( int i = block[l] + 1;i < block[r];i ++ ) ans = max( ans, t[i].calc() );t[block[l]].build_hall();t[block[r]].build_hall();}return ans;
}signed main() {scanf( "%lld", &n );B = sqrt( n );for( int i = 1;i <= n;i ++ ) {scanf( "%lld", &s[i] );s[i] += s[i - 1];block[i] = ( i - 1 ) / B + 1;}for( int i = 1;i <= block[n];i ++ )t[i].init( B * ( i - 1 ) + 1, min( n, B * i ) );int Q, opt, x, y, k;scanf( "%lld", &Q );while( Q -- ) {scanf( "%lld %lld %lld", &opt, &x, &y );if( opt ) printf( "%lld\n", query( x, y ) );else scanf( "%lld", &k ), modify( x, y, k );}return 0;
}
Balanced Lineup
source
code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 50005
#define maxB 250
int n, Q, B;
int block[maxn], h[maxn], Max[maxB], Min[maxB];void solve( int l, int r ) {int maxx = -inf, minn = inf;for( int i = l;i <= min( block[l] * B, r );i ++ )maxx = max( maxx, h[i] ), minn = min( minn, h[i] );for( int i = block[l] + 1;i < block[r];i ++ )maxx = max( maxx, Max[i] ), minn = min( minn, Min[i] );for( int i = max( l, ( block[r] - 1 ) * B + 1 );i <= r;i ++ )maxx = max( maxx, h[i] ), minn = min( minn, h[i] );printf( "%d\n", maxx - minn );
}int main() {scanf( "%d %d", &n, &Q );B = sqrt( n );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &h[i] );block[i] = ( i - 1 ) / B + 1;}memset( Min, 0x3f, sizeof( Min ) );for( int i = 1;i <= n;i ++ ) {Max[block[i]] = max( Max[block[i]], h[i] );Min[block[i]] = min( Min[block[i]], h[i] );}while( Q -- ) {int l, r;scanf( "%d %d", &l, &r );solve( l, r );}return 0;
}
Count on a tree II
已经合并到莫队算法里面去了
[ioi2009]Regions
source
将询问按颜色出现次数分块
小于等于n\sqrt nn的就挂在e2e2e2上,统计从根到该点颜色的出现次数
大于n\sqrt nn的就挂在e1e1e1上,统计该点子树内颜色的出现次数
复杂度就是nnn\sqrt nnn
#include <map>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 200005
#define maxR 25005
struct node {int x, y;node(){}node( int X, int Y ) { x = X, y = Y; }bool operator < ( node t ) const {return x == t.x ? y < t.y : x < t.x;}bool operator == ( node t ) {return x == t.x && y == t.y;}
}MS[maxn];
map < node, int > mp;
vector < int > G[maxn], f[maxR], g[maxR];
int n, R, Q, block;
int r[maxn], cnt[maxR], ans[maxn], id[maxn];void dfs1( int u ) {cnt[r[u]] ++;for( auto v : g[r[u]] ) ans[v] += cnt[MS[v].x];for( auto v : G[u] ) dfs1( v );cnt[r[u]] --;
}void dfs2( int u ) { for( auto v : f[r[u]] ) ans[v] -= cnt[MS[v].y];cnt[r[u]] ++;for( auto v : G[u] ) dfs2( v );for( auto v : f[r[u]] ) ans[v] += cnt[MS[v].y];
}int main() {scanf( "%d %d %d %d", &n, &R, &Q, &r[1] );for( int i = 2, x;i <= n;i ++ ) {scanf( "%d %d", &x, &r[i] );G[x].push_back( i );}for( int i = 1;i <= n;i ++ )cnt[r[i]] ++;block = sqrt( n );for( int i = 1, x, y;i <= Q;i ++ ) {scanf( "%d %d", &x, &y );MS[i] = node( x, y );if( mp.count( node( x, y ) ) ) id[i] = mp[node( x, y )];else {id[i] = mp[node( x, y )] = i;if( cnt[y] <= block ) g[y].push_back( i );else f[x].push_back( i );}}memset( cnt, 0, sizeof( cnt ) );dfs1( 1 );dfs2( 1 );for( int i = 1;i <= Q;i ++ )printf( "%d\n", ans[id[i]] );return 0;
}