【地狱副本】数据结构之线段树Ⅲ——区间最值/赋值/修改/历史值操作(HDU5306,Tyvj 1518,【清华集训2015】V,HDU6315,HDU1828,POJ3162)

文章目录

  • Gorgeous Sequence
  • Tyvj 1518 CPU监控
  • 【清华集训2015】V
  • Naive Operations
  • Picture
  • Walking Race

Gorgeous Sequence

HDU5306

操作

  • 区间与xxxmin\rm minmin
  • 查询区间最大值
  • 查询区间和

比较暴力的线段树维护区间

  • Max : 区间最大值
  • sub_max : 严格小于最大值的区间次大值
  • cnt_max : 最大值个数
  • sum : 区间和
  • tag : 区间取min\rm minmin的标记记录值

考虑取min\rm minmin操作走到一个区间上

  • 最大值都不大于取min\rm minmin的对象,说明操作没用,return

  • 如果小于最大值却严格大于次大值

    此时的操作相当于区间加,打标记 sum-=(Max-x)*max_cnt;Max=x

  • 否则暴力走两边

利用势能分析时间复杂度

  • 定义势能函数为∑idi\sum_i d_iidiiii是线段树上的节点,did_idi是这个节点对应的区间中,互不相同的元素个数
  • 初始时,显然势能是O(nlogn)O(\rm nlogn)O(nlogn)
  • 暴力对长度为nnn的区间做min\rm minmin,消耗的时间是O(n)O(n)O(n),势能也会减少O(n)O(n)O(n)
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define maxn 1000005
#define lson num << 1
#define rson num << 1 | 1
struct node {int Max, sub_max, cnt_max, sum, tag;
}t[maxn << 2];
int a[maxn];void pushup( int num ) {if( t[lson].Max > t[rson].Max ) {t[num].Max = t[lson].Max;t[num].cnt_max = t[lson].cnt_max;t[num].sub_max = max( t[lson].sub_max, t[rson].Max );}else if( t[lson].Max < t[rson].Max ) {t[num].Max = t[rson].Max;t[num].cnt_max = t[rson].cnt_max;t[num].sub_max = max( t[rson].sub_max, t[lson].Max );}else {t[num].Max = t[lson].Max;t[num].cnt_max = t[lson].cnt_max + t[rson].cnt_max;t[num].sub_max = max( t[lson].sub_max, t[rson].sub_max );}t[num].sum = t[lson].sum + t[rson].sum;
}void build( int num, int l, int r ) {t[num].Max = t[num].sub_max = t[num].cnt_max = t[num].sum = 0, t[num].tag = -1;if( l == r ) {t[num].Max = t[num].sum = a[l];t[num].sub_max = -1;t[num].cnt_max = 1;return;}int mid = l + r >> 1;build( lson, l, mid );build( rson, mid + 1, r );pushup( num );
}void pushdown( int num ) {if( ! ~ t[num].tag ) return;int val = t[num].tag;if( t[lson].Max > val ) {t[lson].sum -= ( t[lson].Max - val ) * t[lson].cnt_max;t[lson].Max = t[lson].tag = val;}if( t[rson].Max > val ) {t[rson].sum -= ( t[rson].Max - val ) * t[rson].cnt_max;t[rson].Max = t[rson].tag = val;}t[num].tag = -1;
}void modify( int num, int l, int r, int L, int R, int val ) {if( R < l or r < L or t[num].Max <= val ) return;if( L <= l and r <= R and t[num].sub_max < val ) {t[num].sum -= ( t[num].Max - val ) * t[num].cnt_max;t[num].Max = t[num].tag = val;return;}pushdown( num );int mid = l + r >> 1;modify( lson, l, mid, L, R, val );modify( rson, mid + 1, r, L, R, val );pushup( num );
}int query_max( int num, int l, int r, int L, int R ) {if( r < L or R < l ) return -1;if( L <= l and r <= R ) return t[num].Max;pushdown( num );int mid = l + r >> 1;return max( query_max( lson, l, mid, L, R ), query_max( rson, mid + 1, r, L, R ) );
}int query_sum( int num, int l, int r, int L, int R ) {if( r < L or R < l ) return 0;if( L <= l and r <= R ) return t[num].sum;pushdown( num );int mid = l + r >> 1;return query_sum( lson, l, mid, L, R ) + query_sum( rson, mid + 1, r, L, R );
}signed main() {int n, m, T, opt, l, r, x;scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );build( 1, 1, n );while( m -- ) {scanf( "%lld %lld %lld", &opt, &l, &r );switch ( opt ) {case 0 : { scanf( "%lld", &x ); modify( 1, 1, n, l, r, x );break; }case 1 : { printf( "%lld\n", query_max( 1, 1, n, l, r ) ); break; }case 2 : { printf( "%lld\n", query_sum( 1, 1, n, l, r ) ); break; }}}}return 0;
}

Tyvj 1518 CPU监控

BZOJ3064

操作

  • 区间加
  • 区间赋值
  • 查询区间最大值
  • 查询区间历史最大值

线段树维护

  • Max : 区间最大值
  • Hmax : 区间历史最大值
  • add : 区间加标记
  • Hadd : 区间历史最大加标记
  • tag : 区间赋值标记
  • Htag : 区间历史最大赋值标记

假想不合并标记,每个节点上有一个队列(按照时间先进先出),放着所有曾经推过来的标记

下推标记时,将该节点上所有的标记推到两个儿子处,并清空队列

对于每个节点,每次有一个区间加add标记推来时,令Max←Max+add 然后Hmax←max(Hmax,Max)

设推来的加法标记分别为add[1...k]add[1...k]add[1...k],其前缀和为S[1...k]S[1...k]S[1...k]

则打上第iii个标记之后,Max的值为Max+S[i]

所以,Hmax的值为max⁡i=1kMax+S[i]=Max+max⁡i=1kS[i]\max_{i=1}^k Max+S[i]=Max+\max_{i=1}^k S[i]maxi=1kMax+S[i]=Max+maxi=1kS[i]

因此只需记录max⁡i=1kS[i]\max_{i=1}^k S[i]maxi=1kS[i],就能得知该标记队列对节点的影响

合并加法标记时简单求和,前iii个标记合并后恰好等于S[i]S[i]S[i],那么max⁡i=1kS[i]\max_{i=1}^k S[i]maxi=1kS[i]可以表述为标记的历史最大值Hadd

此题含有赋值操作,赋值操作优先级更高,做法略有不同

赋值一次相当于前面所有的加标记和当前最大值都会被改变

所以赋值的时候,先下放所有的加标记,然后清空(包括历史)

同时,在加标记的时候如果已经有了赋值标记,直接把加标记叠加在赋值标记上

同时记录赋值历史的最大值,其很有可能成为历史最大值

#include <cstdio>
#include <iostream>
using namespace std;
#define inf 1e18
#define maxn 100005
#define int long long
#define lson num << 1
#define rson num << 1 | 1
struct node {int Max, Hmax, add, Hadd, tag, Htag;
}t[maxn << 2];
int a[maxn];void build( int num, int l, int r ) {t[num].Max = t[num].Hmax = t[num].tag = t[num].Htag = -inf;t[num].add = t[num].Hadd = 0;if( l == r ) { t[num].Max = t[num].Hmax = a[l]; return; }int mid = ( l + r ) >> 1;build( lson, l, mid );build( rson, mid + 1, r );t[num].Max = t[num].Hmax = max( t[lson].Max, t[rson].Max );
}void pushup( int num ) {t[num].Max = max( t[lson].Max, t[rson].Max );t[num].Hmax = max( t[lson].Hmax, t[rson].Hmax );
}void down( int num, int add, int Hadd ) {if( t[num].Htag != -inf )t[num].Htag = max( t[num].Htag, t[num].tag + Hadd ), t[num].tag += add;elset[num].Hadd = max( t[num].Hadd, t[num].add + Hadd ), t[num].add += add;
}void pushdown( int num, int l, int r ) {if( t[num].tag == -inf and ! t[num].add ) return;t[num].Hmax = max( t[num].Hmax, max( t[num].Htag, t[num].Max + t[num].Hadd ) );if( t[num].add ) {t[num].Max += t[num].add;if( l ^ r ) {down( lson, t[num].add, t[num].Hadd );down( rson, t[num].add, t[num].Hadd ); } }if( t[num].tag != -inf ) {t[num].Max = t[num].tag;if( l ^ r ) {t[lson].tag = t[rson].tag = t[num].tag;t[lson].Htag = max( t[lson].Htag, t[num].Htag );t[rson].Htag = max( t[rson].Htag, t[num].Htag );}}t[num].add = t[num].Hadd = 0;t[num].tag = t[num].Htag = -inf;
}void add( int num, int l, int r, int L, int R, int val ) {pushdown( num, l, r );if( R < l or r < L ) return;if( L <= l and r <= R ) {if( t[num].tag != -inf ) t[num].tag += val, t[num].Htag = max( t[num].Htag, t[num].tag );else t[num].add += val, t[num].Hadd = max( t[num].Hadd, t[num].add );pushdown( num, l, r );return;}pushdown( num, l, r );int mid = ( l + r ) >> 1;add( lson, l, mid, L, R, val );add( rson, mid + 1, r, L, R, val );pushup( num );
}void modify( int num, int l, int r, int L, int R, int val ) {pushdown( num, l, r );if( R < l or r < L ) return;if( L <= l and r <= R ) {t[num].tag = val;t[num].Htag = max( t[num].Htag, val );pushdown( num, l, r );return;}pushdown( num, l, r );int mid = ( l + r ) >> 1;modify( lson, l, mid, L, R, val );modify( rson, mid + 1, r, L, R, val );pushup( num );
}int query_max( int num, int l, int r, int L, int R ) {if( R < l or r < L ) return -inf;pushdown( num, l, r );if( L <= l and r <= R ) return t[num].Max;int mid = ( l + r ) >> 1;return max( query_max( lson, l, mid, L, R ), query_max( rson, mid + 1, r, L, R ) );
}int queryHmax( int num, int l, int r, int L, int R ) {if( R < l or r < L ) return -inf;pushdown( num, l, r );if( L <= l and r <= R ) return t[num].Hmax;int mid = ( l + r ) >> 1;return max( queryHmax( lson, l, mid, L, R ), queryHmax( rson, mid + 1, r, L, R ) );
}signed main() {int n, m, l, r, x; char opt[5];scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );build( 1, 1, n );scanf( "%lld", &m );while( m -- ) {scanf( "%s %lld %lld", opt, &l, &r );switch ( opt[0] ) {case 'Q' : { printf( "%lld\n", query_max( 1, 1, n, l, r ) ); break; }case 'A' : { printf( "%lld\n", queryHmax( 1, 1, n, l, r ) ); break; }case 'P' : { scanf( "%lld", &x ); add( 1, 1, n, l, r, x );   break; }case 'C' : { scanf( "%lld", &x ); modify( 1, 1, n, l, r, x );break; }}}return 0;
}

【清华集训2015】V

UOJ164

整那么高大上的物理电阻屁用没有

操作

  • 区间加
  • 区间减
  • 区间赋值
  • 查询单点值
  • 查询单点历史最大值

这题很巧的转化将多个操作合并成了一种形式

将标记改写成(a,b)形式,标记对值的贡献转移形式改写成x←max(x+a,b)

  • 区间加:(val,-inf)
  • 区间减:(-val,-inf)
  • 区间赋值:(-inf,val)

标记的合并可以推出来,因为加法对取最大值满足分配率

  • 假设原来的标记为(a1,b1),新来标记为(a2,b2)
  • max⁡(x+a1,b1)←(a2,b2)⇒max⁡(max⁡(x+a1,b1)+a2,b2)⇒max⁡(max⁡(x+a1+a2,b1+a2),b2)\max(x+a_1,b_1)\leftarrow (a_2,b_2)\Rightarrow \max\Big(\max(x+a_1,b_1)+a_2,b_2\Big)\Rightarrow \max\Big(\max(x+a_1+a_2,b_1+a_2),b_2\Big)max(x+a1,b1)(a2,b2)max(max(x+a1,b1)+a2,b2)max(max(x+a1+a2,b1+a2),b2)
  • 新来标记合并最后即为x←max⁡(x+a1+a2,max⁡(a2+b1,b2))x\leftarrow \max\Big(x+a_1+a_2,\max(a_2+b_1,b_2)\Big)xmax(x+a1+a2,max(a2+b1,b2))

考虑当前最大值的更新

两个标记取max\rm maxmax相当于两个分段一次函数取max\rm maxmax

max((a1,b1),(a2,b2))=(max(a1,a2),max(b1,b2))\rm max\Big((a_1,b_1),(a_2,b_2))=(max(a_1,a_2),max(b_1,b_2)\Big)max((a1,b1),(a2,b2))=(max(a1,a2),max(b1,b2))

在这里插入图片描述

再考虑历史最大值的更新

(a0,b0)表示当前,(a1,b1)表示历史最大值,(c0,d0)表示传递点当前,(c1,d1)表示传递点历史最大

合并(a0,b0)(c0,d0)(a0+c0,max⁡(b0+c0,d0))\Big(a_0+c_0,\max(b_0+c_0,d_0)\Big)(a0+c0,max(b0+c0,d0))

合并(a1,b1)(c1,d1),先把(c1,d1)作用在(a0,b0)上,(a0+c1,max⁡(b0+c1,d1))\Big(a_0+c_1,\max(b_0+c_1,d_1)\Big)(a0+c1,max(b0+c1,d1))

再和(a1,b1)取max:(max⁡(a1,a0+c1),max⁡(b1,b0+c1,d1))\Big(\max(a_1,a_0+c_1),\max(b_1,b_0+c_1,d_1)\Big)(max(a1,a0+c1),max(b1,b0+c1,d1))

a,b相当于儿子,c,d代表父亲的信息)

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 500005
#define int long long
#define lson num << 1
#define rson num << 1 | 1
struct node {int a, b, maxa, maxb;
}t[maxn << 2];
int w[maxn];
const int inf = 1e18;void build( int num, int l, int r ) {t[num].a = t[num].maxa = 0;t[num].b = t[num].maxb = -inf;if( l == r ) return;int mid = l + r >> 1;build( lson, l, mid );build( rson, mid + 1, r );
}void pushdown( int num ) {if( ! t[num].a and t[num].b == -inf ) return;t[lson].maxa = max( t[lson].maxa, t[lson].a + t[num].maxa );t[lson].maxb = max( t[lson].maxb, max( t[lson].b + t[num].maxa, t[num].maxb ) );t[rson].maxa = max( t[rson].maxa, t[rson].a + t[num].maxa );t[rson].maxb = max( t[rson].maxb, max( t[rson].b + t[num].maxa, t[num].maxb ) );t[lson].a = max( t[lson].a + t[num].a, -inf );t[lson].b = max( t[lson].b + t[num].a, t[num].b );t[rson].a = max( t[rson].a + t[num].a, -inf );t[rson].b = max( t[rson].b + t[num].a, t[num].b );t[num].a = t[num].maxa = 0;t[num].b = t[num].maxb = -inf;
}void modify( int num, int l, int r, int L, int R, int a, int b ) {if( r < L or R < l ) return;if( L <= l and r <= R ) {t[num].a = max( t[num].a + a, -inf );t[num].b = max( t[num].b + a, b );t[num].maxa = max( t[num].a, t[num].maxa );t[num].maxb = max( t[num].b, t[num].maxb );return;}pushdown( num );int mid = l + r >> 1;modify( lson, l, mid, L, R, a, b );modify( rson, mid + 1, r, L, R, a, b );
}int query( int num, int l, int r, int pos, int k ) {if( l == r ) {if( ! k ) return max( w[l] + t[num].a, t[num].b );else return max( w[l] + t[num].maxa, t[num].maxb );}pushdown( num );int mid = l + r >> 1;if( pos <= mid ) return query( lson, l, mid, pos, k );else return query( rson, mid + 1, r, pos, k );
}signed main() {int n, m;scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &w[i] );build( 1, 1, n );for( int i = 1, opt, l, r, x;i <= m;i ++ ) {scanf( "%lld", &opt );switch ( opt ) {case 1 : { scanf( "%lld %lld %lld", &l, &r, &x ), modify( 1, 1, n, l, r, x, 0 ); break; }case 2 : { scanf( "%lld %lld %lld", &l, &r, &x ), modify( 1, 1, n, l, r, -x, 0 ); break; }case 3 : { scanf( "%lld %lld %lld", &l, &r, &x ), modify( 1, 1, n, l, r, -inf, x ); break; }case 4 : { scanf( "%lld", &x ), printf( "%lld\n", query( 1, 1, n, x, 0 ) ); break; }case 5 : { scanf( "%lld", &x ), printf( "%lld\n", query( 1, 1, n, x, 1 ) ); break; }}}return 0;
}

Naive Operations

HDU6315

刚开始区间全为000,每次区间只+1+1+1

记录区间的最小值,

当最小值为000的时候,说明多叠加了一个bib_ibi的倍数

答案增加111,然后重新把最小值置位bib_ibi (这俩操作要走到叶子节点后再实行)

否则就打上整体−1-11的标记

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 100005
#define int long long
#define lson num << 1
#define rson num << 1 | 1
struct node {int sum, tag, Min;
}t[maxn << 2];
int b[maxn];void build( int num, int l, int r ) {t[num].tag = t[num].sum = 0;if( l == r ) { t[num].Min = b[l]; return; }int mid = l + r >> 1;build( lson, l, mid );build( rson, mid + 1, r );t[num].Min = min( t[lson].Min, t[rson].Min );
}void pushdown( int num ) {if( ! t[num].tag ) return;t[lson].tag += t[num].tag;t[rson].tag += t[num].tag;t[lson].Min -= t[num].tag;t[rson].Min -= t[num].tag;t[num].tag = 0;
}void modify( int num, int l, int r, int L, int R ) {if( R < l or r < L ) return;if( L <= l and r <= R ) {t[num].Min --;if( t[num].Min ) { t[num].tag ++; return; }else if( l == r ) { t[num].sum ++, t[num].Min = b[l]; return; }}pushdown( num );int mid = l + r >> 1;modify( lson, l, mid, L, R );modify( rson, mid + 1, r, L, R );t[num].sum = t[lson].sum + t[rson].sum;t[num].Min = min( t[lson].Min, t[rson].Min );
}int query( int num, int l, int r, int L, int R ) {if( r < L or R < l ) return 0;if( L <= l and r <= R ) return t[num].sum;pushdown( num );int mid = l + r >> 1;return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );
}signed main() {int n, Q, l, r; char opt[10];while( ~ scanf( "%lld %lld", &n, &Q ) ) {for( int i = 1;i <= n;i ++ ) scanf( "%lld", &b[i] );build( 1, 1, n );for( int i = 1;i <= Q;i ++ ) {scanf( "%s %d %d", opt, &l, &r );if( opt[0] == 'a' ) modify( 1, 1, n, l, r );else printf( "%lld\n", query( 1, 1, n, l, r ) );}}return 0;
}

Picture

HDU1828

扫描线求矩阵周长模板题

img

从下往上扫描线扫,横线长度:现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度之差的绝对值

而竖线长度为,区间的段数*2,乘以222是因为一段区间左右各一条

e.g. 段数cntcntcnt的计算

  • 若区间[0,10]被[1,2][4,5]覆盖,则cnt=2
  • 若区间[0,10]被[1,3][4,5]覆盖,则cnt=1(两区间刚好连在一起)
  • 若区间[0,10]被[1,5][2,6]覆盖,则cnt=1(两区间连起来还是一段)

扫描线中的线段树的一个节点代表一个单位长度线段

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 200005
#define lson num << 1
#define rson num << 1 | 1
struct node {int l, r, h, op;node(){}node( int L, int R, int H, int Op ) {l = L, r = R, h = H, op = Op;}
}E[maxn];
struct tree {int l, r, len, cnt, tag, flag_l, flag_r;
}t[maxn << 2];bool cmp( node x, node y ) { return x.h < y.h; }void build( int num, int l, int r ) {t[num].l = l, t[num].r = r;t[num].len = t[num].cnt = t[num].tag = t[num].flag_l = t[num].flag_r = 0;if( l == r ) return;int mid = l + r >> 1;build( lson, l, mid );build( rson, mid + 1, r );
}void pushup( int num ) {if( t[num].tag ) {t[num].len = t[num].r - t[num].l + 1;t[num].cnt = t[num].flag_l = t[num].flag_r = 1;}else if( t[num].l == t[num].r )t[num].len = t[num].cnt = t[num].flag_l = t[num].flag_r = 0;else {t[num].len = t[lson].len + t[rson].len;t[num].cnt = t[lson].cnt + t[rson].cnt - ( t[lson].flag_r and t[rson].flag_l );t[num].flag_l = t[lson].flag_l, t[num].flag_r = t[rson].flag_r;}
}void modify( int num, int l, int r, int val ) {if( t[num].r < l or r < t[num].l ) return;if( l <= t[num].l and t[num].r <= r ) {t[num].tag += val;pushup( num );return;}modify( lson, l, r, val );modify( rson, l, r, val );pushup( num );
}int Fabs( int x ) { return x < 0 ? -x : x; }int main() {int n, x1, y1, x2, y2;while( ~ scanf( "%d", &n ) ) {int L = 1e9, R = -1e9;for( int i = 1;i <= n;i ++ ) {scanf( "%d %d %d %d", &x1, &y1, &x2, &y2 );E[i] = node( x1, x2, y1, 1 );E[i + n] = node( x1, x2, y2, -1 );L = min( L, x1 );R = max( R, x2 );}n <<= 1; R --;sort( E + 1, E + n + 1, cmp );build( 1, L, R );int ans = 0, lst = 0;for( int i = 1;i <= n;i ++ ) {modify( 1, E[i].l, E[i].r - 1, E[i].op );ans += Fabs( t[1].len - lst ) + 2 * t[1].cnt * ( E[i + 1].h - E[i].h );lst = t[1].len;}printf( "%d\n", ans );}return 0;
}

Walking Race

POJ3162

用两次栈模拟dpdpdp求出以每个点为端点的最长路径

用线段树维护区间内的路径最大值/最小值

尺取法,双指针判断区间[l,r][l,r][l,r]是否在mmm限制内

#include <stack>
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 1000005
#define lson num << 1
#define rson num << 1 | 1
const int inf = 1e9;
int n, m;
bool vis[maxn];
int maxlen[maxn];
stack < int > sta;
vector < pair < int, int > > G[maxn];struct node { int fa, d, Max, id, sub_max, sub_id;void clear( int f, int dis ) { fa = f, d = dis, Max = id = sub_max = sub_id = 0; }	
}MS[maxn];void dfs1() {for( int i = 1;i <= n;i ++ ) vis[i] = 0;sta.push( 1 ), MS[1].clear( 0, 0 );while( ! sta.empty() ) {int u = sta.top();if( ! vis[u] )for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, dis = G[u][i].second;if( v == MS[u].fa ) continue;else MS[v].clear( u, dis ), sta.push( v );}else {sta.pop();for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, dis = G[u][i].second;int len = MS[v].Max + dis;if( len > MS[u].Max ) {MS[u].sub_max = MS[u].Max;MS[u].sub_id = MS[u].id;MS[u].Max = len;MS[u].id = v;}else if( len > MS[u].sub_max ) {MS[u].sub_max = len;MS[u].sub_id = v;}}}vis[u] = 1;}
}void dfs2() {sta.push( 1 );while( ! sta.empty() ) {int u = sta.top(); sta.pop();for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first;if( v == MS[u].fa ) continue;else sta.push( v );}maxlen[u] = MS[u].Max;if( u == 1 ) continue;else {int fa = MS[u].fa, len;if( MS[fa].id == u ) len = MS[fa].sub_max + MS[u].d;else len = MS[fa].Max + MS[u].d;maxlen[u] = max( maxlen[u], len );if( len > MS[u].Max ) {MS[u].sub_max = MS[u].Max;MS[u].sub_id = MS[u].id;MS[u].Max = len;MS[u].id = fa;}else if( len > MS[u].sub_max ) {MS[u].sub_max = len;MS[u].sub_id = fa;}}}
}struct tree { int Min, Max; }t[maxn << 2];void build( int num, int l, int r ) {if( l == r ) { t[num].Min = t[num].Max = maxlen[l]; return; }int mid = l + r >> 1;build( lson, l, mid );build( rson, mid + 1, r );t[num].Max = max( t[lson].Max, t[rson].Max );t[num].Min = min( t[lson].Min, t[rson].Min );
}int query_min( int num, int l, int r, int L, int R ) {if( r < L or R < l ) return inf;if( L <= l and r <= R ) return t[num].Min;int mid = l + r >> 1;return min( query_min( lson, l, mid, L, R ), query_min( rson, mid + 1, r, L, R ) );
}int query_max( int num, int l, int r, int L, int R ) {if( r < L or R < l ) return -inf;if( L <= l and r <= R ) return t[num].Max;int mid = l + r >> 1;return max( query_max( lson, l, mid, L, R ), query_max( rson, mid + 1, r, L, R ) );
}int main() {int l, r, minn, maxx;while( ~ scanf( "%d %d", &n, &m ) ) {for( int i = 1;i <= n;i ++ ) G[i].clear();for( int i = 2, fa, d;i <= n;i ++ ) {scanf( "%d %d", &fa, &d );G[fa].push_back( make_pair( i, d ) );}dfs1(), dfs2(), build( 1, 1, n );l = r = 1, minn = maxx = maxlen[1];int ans = 0;while( l <= r and r <= n ) {if( maxx - minn <= m ) {ans = max( ans, r - l + 1 );r ++;minn = min( minn, maxlen[r] );maxx = max( maxx, maxlen[r] );}else {l ++;minn = query_min( 1, 1, n, l, r );maxx = query_max( 1, 1, n, l, r );}if( ans > n - l ) break;}printf( "%d\n", ans );}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Acwing 1089. 烽火传递

Acwing 1089. 烽火传递 题意&#xff1a; 有n个数&#xff0c;要保证每m个数中必须选一个&#xff0c;问所选数的最小总和是多少 题解&#xff1a; 我一开始设的状态为:dp[i]表示前i个数选完的最小值&#xff0c;第i个数可以选也可以不选&#xff0c;但是这样一个状态&…

IIS作为ASP.NET Core2.1 反向代理服务器未说的秘密

--以下内容针对 ASP.NET Core2.1&#xff0c;2.2出现IIS进程内寄宿 暂不展开讨论---相比ASP.NET&#xff0c;出现了3个新的组件:ASP.NET Core Module、Kestrel、dotnet.exe&#xff0c; 后面我们会理清楚这三个组件的作用和组件之间的交互原理。 ASP.NET Core 设计的初衷是开源…

程序员修神之路--分布式缓存的一条明路(附代码)

菜菜呀&#xff0c;由于公司业务不断扩大&#xff0c;线上分布式缓存服务器扛不住了呀程序员主力 Y总如果加硬件能解决的问题&#xff0c;那就不需要修改程序菜菜我是想加服务器来解决这个问题&#xff0c;但是有个问题呀程序员主力 Y总&#xff1f;&#xff1f;&#xff1f;菜…

长沙.NET技术社区正式成立

感谢大家的关注&#xff0c;请允许我冒昧的向大家汇报长沙.NET技术社区第一次交流会的会议进展情况。活动过程汇报2019年2月17日&#xff0c;继深圳&#xff0c;广州&#xff0c;西安&#xff0c;成都&#xff0c;苏州相继成立了.net社区之后&#xff0c;酝酿已久的长沙.net社区…

Asp.NetCore轻松学-部署到 IIS 进行托管

前言经过一段时间的学习&#xff0c;终于来到了部署服务这个环节&#xff0c;.NetCore 的部署方式非常的灵活多样&#xff0c;但是其万变不离其宗&#xff0c;所有的 Asp.NetCore 程序都基于端口的侦听&#xff0c;在部署的时候仅需要配置侦听地址、端口&#xff08;一个或者多…

响应式编程知多少 | Rx.NET 了解下

1. 引言An API for asynchronous programming with observable streams. ReactiveX is a combination of the best ideas from the Observer pattern, the Iterator pattern, and functional programming.ReactiveX 使用可观察数据流进行异步编程的API。 ReactiveX结合了观察者…

.NET Core中的验证组件FluentValidation的实战分享

今天有人问我能不能出一篇FluentValidation的教程&#xff0c;刚好今天在实现我们的.NET Core实战项目之CMS的修改密码部分的功能中有用到FluentValidation&#xff0c;所以就以修改用户密码为实例来为大家进行一下ASP.NET Core中的验证组件FluentValidation的实战分享&#xf…

笛卡尔树详解带建树模板及例题运用(Largest Submatrix of All 1’s,洗车 Myjnie,Removing Blocks,SPOJ PERIODNI)

文章目录笛卡尔树介绍例题Largest Submatrix of All 1’s应用「POI2015」洗车 Myjnie[AGC028B] Removing BlocksSPOJ PERIODNI笛卡尔树 介绍 笛卡尔树是一种数据结构&#xff0c;每个点由两个值&#xff0c;键值key和权值val&#xff0c;组成 其键值满足二叉树性质 即点的左子…

如何为ASP.NET Core设置客户端IP白名单验证

本篇博文中展示了如何在ASP.NET Core应用程序中设置IP白名单验证的3种方式。你可以使用一下3种方式&#xff1a;使用中间件检查每个请求的远程IP地址使用Action过滤器为指定的Controller或action方法添加针对远程IP地址的检查使用IPageFilter为Razor Pages应用添加针对远程IP地…

让ASP.NET Core支持GraphQL之-GraphQL的实现原理

众所周知RESTful API是目前最流行的软件架构风格之一&#xff0c;它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁&#xff0c;更有层次&#xff0c;更易于实现缓存等机制。RESTful的优越性是毋庸置疑的&#xff0c;不过GraphQL也可以作为一种补充&am…

[2021-09-02 contest]CF1251C,可达性统计(bitset优化dp),Boomerang Tournament(状压dp),小蓝的好友(mrx)(treap平衡树)

文章目录CF1251C Minimize The Integeracwing164&#xff1a;可达性统计Facebook Hacker Cup 2016 Round 1 Boomerang Tournament[Zjoi2012]小蓝的好友(mrx)CF1251C Minimize The Integer ………………… 给你一个大整数aaa&#xff0c;它由nnn位数字&#xff0c;也可能有前导…

Entity Framework 的一些性能建议

点击上方蓝字关注“汪宇杰博客”这是一篇我在2012年写的老文章&#xff0c;至今适用&#xff08;没错&#xff0c;我说的就是适用于EF Core&#xff09;。因此使用微信重新推送&#xff0c;希望能帮到大家。自从我用了EF&#xff0c;每次都很关心是否有潜在的性能问题。所以每次…

微软内部全面拥抱开源流程Inner Source

微软过去几年一直是 GitHub 平台上开源贡献者最多的公司。不仅如此&#xff0c;微软还将继续拥抱开源&#xff0c;内部有一项名为 Inner Source 的计划&#xff0c;将开源开发流程引入到公司内部。事实上&#xff0c;Inner Source 已经存在于微软内部多年&#xff0c;包括更多代…

k8s使用helm打包chart并上传到腾讯云TencentHub

本文只涉及Helm的Chart操作&#xff0c;不会对其他知识进行过多描述。至于安装这块&#xff0c;麻烦自行百度吧&#xff0c;一大堆呢。在容器化的时代&#xff0c;我们很多应用都可以部署在docker&#xff0c;很方便&#xff0c;而再进一步&#xff0c;我们还有工具可以对docke…

数据结构之基环树——骑士,Island,旅行加强版,Number of Simple Paths,Traffic Network in Numazu,Card Game

文章目录[ZJOI2008]骑士[IOI2008] Island[NOIP2018 提高组] 旅行 加强版CF1454E Number of Simple PathsTraffic Network in NumazuCard Game基环树的常见解法若干个基环树互相独立断环为链&#xff08;随便断一条&#xff09;环外树和环外树之间的树形DP环变链后整体可以用数据…

如何在ASP.NET Core中自定义Azure Storage File Provider

主题&#xff1a;如何在ASP.NET Core中自定义Azure Storage File Provider作者&#xff1a; Lamond Lu地址: https://www.cnblogs.com/lwqlun/p/10406566.html项目源代码&#xff1a; https://github.com/lamondlu/AzureFileProvider背景ASP.NET Core是一个扩展性非常高的框架…

美好生活从撸好代码开始

楔子 昨天晚上做了个梦&#xff0c;梦到老板对我说了一番道理&#xff0c;他说对家庭要用爱心&#xff0c;做人对社会要有包容心&#xff0c;对工作要有责任心&#xff0c;对老板要有同理心。 我深以为然。现在的老板确实太不容易了&#xff0c;尤其是作为一家承载梦想&#xf…

Dotnet全平台下APM-Trace探索

随着支撑的内部业务系统越来越多&#xff0c;向着服务化架构进化&#xff0c;在整个迭代过程中&#xff0c;会逐渐暴露出以下问题。传统依赖于应用服务器日志等手段的排除故障原因的复杂度越来越高&#xff0c;传统的监控服务已经无法满足需求。终端--> Nginx --> IIS --…

部署Chart应用并使用.net core读取Kubernetes中的configMap

上一篇文章讲了 k8s使用helm打包chart并上传到腾讯云TencentHub&#xff0c;今天就讲一下使用Helm部署应用并使用configMap代替asp.net core 中的appsettings.json文件。把Chart上传到TencentHub之后&#xff0c;我们就可以通过腾讯云的容器服务&#xff0c;直接部署Helm应用了…

EFCore Lazy Loading + Inheritance = 干净的数据表 (一)

前言α角 与 β角关于α角 与 β角的介绍&#xff0c;请见上文 如何用EFCore Lazy Loading实现Entity Split。本篇会继续有关于β角的彩蛋在等着大家去发掘。/斜眼笑其他本篇的程序&#xff0c;可以在 https://github.com/kentliu2007/EFCoreDemo/tree/master/InheritanceWithE…