8.9 数据结构
P2824 [HEOI2016/TJOI2016] 排序
玛丽太差了 急
错误:
- \(cov\)不清零
- 排序的时候区间修改范围错了
- 需要判断\(x>y\)的情况
一道很巧妙的题
我们二分最后\(q\)位置的数\(ans\) 将大于等于\(ans\)的数标记为\(1\) 否则为\(0\)
那么我们对于\(01\)序列进行多次排序之后 如果这个点上的值为\(1\) 那么说明取值\(mid\)是合法的
下界越小越为\(1\) 下界越大越为\(0\) 那么我们需要取得最大的\(1\)位置 即为\(r\)
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#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] , qq;
struct que { int op , l , r; } q[N];
struct seg
{
struct node { int sum , cov; } t[N<<2];
inl void up ( int p ) { t[p].sum = t[ls].sum + t[rs].sum; }
inl void pushcov ( int p , int l , int r , int val ) { t[p].sum = ( r - l + 1 ) * val , t[p].cov = val; }
inl void down ( int p , int l , int r )
{
if ( t[p].cov != -1 )
{
pushcov ( lson , t[p].cov );
pushcov ( rson , t[p].cov );
}
t[p].cov = -1;
}
void build ( int p , int l , int r , int x )
{
t[p].cov = -1;
if ( l == r ) return t[p].sum = ( a[l] >= x ) , void();
build ( lson , x ) , build ( rson , x ) , up(p);
}
void upd ( int p , int l , int r , int x , int y , int val )
{
if ( x > y ) return;
if ( x <= l && r <= y ) return pushcov ( 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);
}
int query ( int p , int l , int r , int x , int y )
{
if ( x > y ) return 0;
if ( x <= l && r <= y ) return t[p].sum;
int res = 0; down(p,l,r);
if ( x <= mid ) res += query ( lson , x , y );
if ( mid + 1 <= y ) res += query ( rson , x , y );
return res;
}
int querypoint ( int p , int l , int r , int x )
{
if ( l == r ) return t[p].sum;
down(p,l,r);
if ( x <= mid ) return querypoint ( lson , x );
else return querypoint ( rson , x );
}
}T;
int check ( int x )
{
T.build ( 1 , 1 , n , x );
for ( int i = 1 ; i <= m ; i ++ )
{
int l = q[i].l , r = q[i].r , op = q[i].op;
int tmp = T.query ( 1 , 1 , n , l , r );
if ( op == 1 )//降序
{
T.upd ( 1 , 1 , n , l , l + tmp - 1 , 1 );
T.upd ( 1 , 1 , n , l + tmp , r , 0 );
}
else //升序
{
T.upd ( 1 , 1 , n , l , r - tmp , 0 );
T.upd ( 1 , 1 , n , r - tmp + 1 , r , 1 );
}
}
return T.querypoint ( 1 , 1 , n , qq );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , m = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 ; i <= m ; i ++ ) q[i].op = read() , q[i].l = read() , q[i].r = read();
qq = read();
int l = 1 , r = n;
while ( l <= r )
{
if ( check(mid) ) l = mid + 1;
else r = mid - 1;
}
cout << r << endl;
return 0;
}
P2633 Count on a tree
用主席树维护从根节点到该节点的所有点权即可 查询路径时用四棵树差分查询(也就是\(u,v,lca(u,v),fa[lca(u,v)]\))
在\(dfs2\)中没有特判\(son[u]\)导致\(TLE\) 急急急急急
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define ls(p) t[p].son[0]
#define rs(p) t[p].son[1]
#define lson ls(p),l,mid
#define rson rs(p),mid+1,r
#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 , lstans , a[N] , rt[N];
int fa[N] , dep[N] , son[N] , sz[N];
int top[N];
vector<int> lsh , e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
struct LCA
{
void dfs1 ( int u , int f )
{
fa[u] = f , dep[u] = dep[f] + 1 , sz[u] = 1;
for ( auto v : e[u] )
if ( v ^ f )
{
dfs1 ( v , u );
sz[u] += sz[v];
if ( sz[son[u]] < sz[v] ) son[u] = v;
}
}
void dfs2 ( int u , int tp )
{
top[u] = tp;
if ( son[u] ) dfs2 ( son[u] , tp );
for ( auto v : e[u] ) if ( v ^ fa[u] && v ^ son[u] ) dfs2 ( v , v );
}
int lca ( int u , int v )
{
while ( top[u] != top[v] )
{
if ( dep[top[u]] < dep[top[v]] ) swap ( u , v );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u , v );
return v;
}
}L;
struct seg
{
struct node { int son[2] , sum; } t[N<<5];
int tot = 0;
inl int new_node ( int p ) { t[++tot] = t[p]; return tot; }
inl void up ( int p ) { t[p].sum = t[ls(p)].sum + t[rs(p)].sum; }
void upd ( int &p , int l , int r , int x )
{
p = new_node(p); t[p].sum ++;
if ( l == r ) return;
if ( x <= mid ) upd ( lson , x );
else upd ( rson , x );
}
int query ( int u , int v , int f , int ff , int l , int r , int k )
{
if ( l == r ) return l;
int tmp = t[ls(u)].sum + t[ls(v)].sum - t[ls(f)].sum - t[ls(ff)].sum;
if ( k <= tmp ) return query ( ls(u) , ls(v) , ls(f) , ls(ff) , l , mid , k );
else return query ( rs(u) , rs(v) , rs(f) , rs(ff) , mid + 1 , r , k - tmp );
}
}T;
void dfs ( int u , int f )
{
rt[u] = rt[f] , T.upd ( rt[u] , 1 , n , a[u] );
for ( auto v : e[u] ) if ( v ^ f ) dfs ( v , u );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , m = 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() + 1;
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
L.dfs1 ( 1 , 0 ) , L.dfs2 ( 1 , 1 ) , dfs ( 1 , 0 );
for ( int i = 1 ; i <= m ; i ++ )
{
int u = read() ^ lstans , v = read() , k = read();
cout << ( lstans = lsh[T.query ( rt[u] , rt[v] , rt[L.lca(u,v)] , rt[fa[L.lca(u,v)]] , 1 , n , k )-1] ) << endl;
}
return 0;
}
P1502 窗口的星星
扫描线 处理的是二位平面内的点问题
相当于用一根线从下到上扫描 用一棵线段树维护这根线
对于本题 可以做如下转化:
- 将每一颗星星转化为一个矩形 矩形中的点就是可以包括这个点的窗口右上点
- 那么我们可以用扫描线维护这个右上点 对于扫描线的每一个位置用线段树维护这个右上点的最优位置的权值(也就是这条线上的最大值)
注意到题目是不算边框的 那么我们能覆盖到这个矩形的区间范围就要减一
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#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 , w , h , maxx;
struct node { int l , r , h , val; };
vector<node> seg;
vector<int> lsh;
struct segtree
{
struct node { int maxx , add; } t[N<<2];
inl void up ( int p ) { t[p].maxx = max ( t[ls].maxx , t[rs].maxx ); }
inl void pushadd ( int p , int val ) { t[p].maxx += val , t[p].add += val; }
inl void down ( int p ) { if ( t[p].add ) pushadd ( ls , t[p].add ) , pushadd ( rs , t[p].add ); t[p].add = 0; }
void build ( int p , int l , int r )
{
t[p].add = t[p].maxx = 0;
if ( l == r ) return;
build ( lson ) , build ( rson );
}
void upd ( int p , int l , int r , int x , int y , int val )
{
if ( x <= l && r <= y ) return pushadd ( p , val ) , void();
down(p);
if ( x <= mid ) upd ( lson , x , y , val );
if ( mid + 1 <= y ) upd ( rson , x , y , val );
up(p);
}
int query ( int p , int l , int r , int x , int y )
{
if ( x <= l && r <= y ) return t[p].maxx;
int res = 0; down(p);
if ( x <= mid ) res = max ( res , query ( lson , x , y ) );
if ( mid + 1 <= y ) res = max ( res , query ( rson , x , y ) );
return res;
}
}T;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
int TT = read();
while ( TT -- )
{
lsh.clear() , seg.clear() , maxx = 0;
n = read() , w = read() , h = read();
for ( int i = 1 ; i <= n ; i ++ )
{
int x = read() , y = read() , l = read();
lsh.eb(x) , lsh.eb(x+w-1);
seg.eb ( (node) { x , x + w - 1 , y , l } ); seg.eb ( (node) { x , x + w - 1 , y + h - 1 , -l } );
}
sort ( lsh.begin() , lsh.end() );
lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
n = lsh.size() , T.build ( 1 , 1 , n );
sort ( seg.begin() , seg.end() , [](const node &a , const node &b) { return a.h == b.h ? a.val > b.val : a.h < b.h; } );
for ( auto [l,r,h,val] : seg )
{
l = lower_bound ( lsh.begin() , lsh.end() , l ) - lsh.begin() + 1;
r = lower_bound ( lsh.begin() , lsh.end() , r ) - lsh.begin() + 1;
T.upd ( 1 , 1 , n , l , r , val );
maxx = max ( maxx , T.query ( 1 , 1 , n , 1 , n ) );
}
cout << maxx << endl;
}
return 0;
}
P4198 楼房重建
线段树思维题
显然想到为每一个点维护斜率
处理合并的时候 我们要处理左面\(1\)点能看到的所有斜率 那么我们先加上左面能看到的答案 再加上右面大于左面最大斜率的所有答案
处理询问的时候 如果左面的\(maxx\)小于当前查询的\(maxx\) 那么查询右子树
否则查询左面的权值加上右面的答案 因为右面的合法答案一定是大于左面的最大值的 注意右面的答案必须用\(sum[p]-sum[ls]\)而不是\(sum[rs]\) 因为右面可能会被左面挡住
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#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 , lstans , a[N] , rt[N];
struct kk
{
struct node { int sum; double maxx; } t[N<<2];
int query ( int p , int l , int r , double maxx )
{
if ( t[p].maxx <= maxx ) return 0;
if ( l == r ) return 1;
if ( t[ls].maxx <= maxx ) return query ( rson , maxx );
else return query ( lson , maxx ) + t[p].sum - t[ls].sum;
}
void upd ( int p , int l , int r , int x , double val )
{
if ( l == r ) return t[p].sum = 1 , t[p].maxx = val , void();
if ( x <= mid ) upd ( lson , x , val );
else upd ( rson , x , val );
t[p].maxx = max ( t[ls].maxx , t[rs].maxx );
t[p].sum = t[ls].sum + query ( rson , t[ls].maxx );
}
}T;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
n = read() , m = read();
for ( int i = 1 ; i <= m ; i ++ )
{
int u = read() , v = read();
T.upd ( 1 , 1 , n , u , (double)v/u );
cout << T.t[1].sum << endl;
}
return 0;
}