8.13 杂题
P1471 方差
我们把方差公式展开:

所以只需要维护一个区间平方和和区间和
当我们更新一个区间加时

\(pushdown\) 易得
注意 \(double\) 的使用
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
const int N = 1e5 + 5;
// char buf[1<<24] , *p1 , *p2;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m;
double a[N];
struct Tree
{
struct node { double sum , sqrsum , add; } t[N<<2];
inl void pushadd ( int p , int l , int r , double val ) { t[p].add += val , t[p].sqrsum += 2 * t[p].sum * val + ( r - l + 1 ) * val * val , t[p].sum += ( r - l + 1 ) * val; }
inl void down ( int p , int l , int r ) { if ( t[p].add ) pushadd ( lson , t[p].add ) , pushadd ( rson , t[p].add ) , t[p].add = 0; }
inl void up ( int p ) { t[p].sum = t[ls].sum + t[rs].sum , t[p].sqrsum = t[ls].sqrsum + t[rs].sqrsum; }
void build ( int p , int l , int r )
{
if ( l == r ) return t[p].sum = a[l] , t[p].sqrsum = a[l] * a[l] , void();
build ( lson ) , build ( rson ) , up(p);
}
void upd ( int p , int l , int r , int x , int y , double val )
{
if ( x <= l && r <= y ) return pushadd ( p , l , r , val ) , void();
down ( p , l , r );
if ( x <= mid ) upd ( lson , x , y , val );
if ( mid + 1 <= y ) upd ( rson , x , y , val );
up(p);
}
double query1 ( int p , int l , int r , int x , int y )
{
if ( x <= l && r <= y ) return t[p].sum;
double res = 0; down ( p , l , r );
if ( x <= mid ) res += query1 ( lson , x , y );
if ( mid + 1 <= y ) res += query1 ( rson , x , y );
return res;
}
double query2 ( int p , int l , int r , int x , int y )
{
if ( x <= l && r <= y ) return t[p].sqrsum;
double res = 0; down ( p , l , r );
if ( x <= mid ) res += query2 ( lson , x , y );
if ( mid + 1 <= y ) res += query2 ( rson , x , y );
return res;
}
}T;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) cin >> a[i];
T.build ( 1 , 1 , n );
for ( int i = 1 ; i <= m ; i ++ )
{
int op = read() , l = read() , r = read(); double w;
if ( op == 1 ) cin >> w , T.upd ( 1 , 1 , n , l , r , w );
if ( op == 2 ) cout << fixed << setprecision(4) << T.query1 ( 1 , 1 , n , l , r ) / ( 1.0 * ( r - l + 1 ) ) << endl;
if ( op == 3 )
{
double temp1 = T.query1 ( 1 , 1 , n , l , r ) / ( 1.0 * ( r - l + 1 ) );
double temp2 = T.query2 ( 1 , 1 , n , l , r ) / ( 1.0 * ( r - l + 1 ) );
cout << fixed << setprecision(4) << temp2 - temp1 * temp1 << endl;
}
}
return 0;
}
P5906 【模板】回滚莫队&不删除莫队
回滚莫队总是细节很多......
这题加点操作很好维护 但是删点操作很难维护 那么考虑使用回滚莫队
那么我们记录\(st[a[i]]\)数组和\(ed[a[i]]\)数组表示最早的\(a[i]\)的出现位置即可
对于滚动的左端点 单独记录\(tempst\)和\(temped\)两个数组即可
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
const int N = 2e5 + 5;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , a[N] , st[N] , ed[N] , cnt[N] , bel[N] , block , tot , ll[N] , rr[N] , tmp[N] , l , r , lstblock , ans[N] , res , tempst[N] , temped[N];
vector<int>lsh;
struct que { int l , r , id; } q[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , lsh.eb(a[i]);
sort ( lsh.begin() , lsh.end() );
lsh.erase ( unique ( lsh.begin() , lsh.end() ) , lsh.end() );
for ( int i = 1 ; i <= n ; i ++ ) a[i] = lower_bound ( lsh.begin() , lsh.end() , a[i] ) - lsh.begin();
block = sqrt(n) , tot = n / block;
if ( n % block ) tot ++;
for ( int i = 1 ; i <= n ; i ++ ) bel[i] = ( i - 1 ) / block + 1;
for ( int i = 1 ; i <= tot ; i ++ ) ll[i] = ( i - 1 ) * block + 1 , rr[i] = i * block; rr[tot] = n;
m = read();
for ( int i = 1 ; i <= m ; i ++ ) q[i].l = read() , q[i].r = read() , q[i].id = i;
sort ( q + 1 , q + m + 1 , [](const que &a , const que &b) { return bel[a.l] == bel[b.l] ? a.r < b.r : bel[a.l] < bel[b.l]; } );
l = 1 , r = 0;
for ( int i = 1 ; i <= m ; i ++ )
{
if ( bel[q[i].l] == bel[q[i].r] )
{
int temp = 0;
for ( int j = q[i].l ; j <= q[i].r ; j ++ ) tmp[a[j]] = j;
for ( int j = q[i].l ; j <= q[i].r ; j ++ ) temp = max ( temp , tmp[a[j]] - j );
ans[q[i].id] = temp;
for ( int j = q[i].l ; j <= q[i].r ; j ++ ) tmp[a[j]] = 0;
continue;
}
if ( lstblock ^ bel[q[i].l] )
{
for ( int j = l ; j <= r ; j ++ ) st[a[j]] = ed[a[j]] = 0;
l = rr[bel[q[i].l]] + 1 , r = rr[bel[q[i].l]];
res = 0; lstblock = bel[q[i].l];
}
while ( r < q[i].r ) { ++ r; if ( !st[a[r]] ) st[a[r]] = r; ed[a[r]] = r , res = max ( res , ed[a[r]] - st[a[r]] ); }
int temp = res , _l = l;
while ( q[i].l < _l ) { -- _l; if ( !temped[a[_l]] ) temped[a[_l]] = _l; tempst[a[_l]] = _l , res = max ( res , max ( temped[a[_l]] , ed[a[_l]] ) - tempst[a[_l]] ); }
ans[q[i].id] = res;
while ( _l < l ) tempst[a[_l]] = temped[a[_l]] = 0 , ++_l;
res = temp;
}
for ( int i = 1 ; i <= m ; i ++ ) cout << ans[i] << endl;
return 0;
}
P4147 玉蟾宫
先预处理每一个点能向上延伸多远的距离
那么我们对于每一行维护一个单调递增的单调栈 栈中记录\(hei\)和\(wei\)两个数表示这个块的宽度和高度
每次将高度大于等于当前高度的栈顶都弹出 每一次弹栈都统计答案 记录 \(temp\) 表示能扩展的最大宽度即可
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
const int N = 1e3 + 5;
// char buf[1<<24] , *p1 , *p2;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , pos[N][N] , ans;
struct que { int wei , hei; } sta[10000+5];
void solve ( int i )
{
int top = 0 , temp = 0;
sta[++top] = { 1 , pos[i][1] };
for ( int j = 2 ; j <= m ; j ++ )
{
temp = 0;
while ( sta[top].hei >= pos[i][j] && top )
{
temp += sta[top].wei;
ans = max ( ans , sta[top--].hei * temp );
}
sta[++top] = { temp + 1 , pos[i][j] };
}
temp = 0;
while ( top > 0 )
{
temp += sta[top].wei;
ans = max ( ans , sta[top--].hei * temp );
}
}
char ch;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= m ; j ++ )
cin >> ch , pos[i][j] = ( ch == 'F' ) ? pos[i-1][j] + 1 : 0;
for ( int i = 1 ; i <= n ; i ++ ) solve ( i );
cout << ans * 3 << endl;
return 0;
}