Luogu题目选做(三)

1|0P2249


1|1二分答案


直接套用lower_bound()

#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int n , m , a[N]; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar(); return x; } int main() { n = read() , m = read(); for( register int i = 1 ; i <= n ; i ++ ) a[i] = read(); for( register int i = 1 , x , pos ; i <= m ; i ++ ) { x = read() , pos = lower_bound( a + 1 , a + 1 + n , x ) - a; printf( "%d " , pos > n || a[pos] > x ? -1 : pos ); } return 0; }

1|2Hash


可以直接用Hash储存每个数第一次出现的的位置

#include<bits/stdc++.h> using namespace std; const int Mod = 1e5+7; int n , m ; vector< pair<int , int > > hash_map[Mod]; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar(); return x; } inline int check( int x , int key ) { for( auto it : hash_map[key] ) if( x == it.first ) return it.second; return -1; } int main() { n = read() , m = read(); for( register int i = 1 , x , key , f ; i <= n ; i ++ ) { x = read() , key = x % Mod , f = 0; if( check( x , key ) == -1 ) hash_map[key].emplace_back( x , i ); } for( register int i = 1 , x ; i <= m ; i ++ ) x = read() , printf("%d " , check( x , x % Mod ) ); return 0; }

2|0P2068


树状数组模板题

#include <bits/stdc++.h> using namespace std; #define ll long long #define lowbit( x ) ( x & -x ) const int N = 1e5 + 5; int n , m ; ll bit[N]; inline int read() { int x = 0; char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar(); return x; } inline bool opt() { char ch = getchar(); while( ch != 'x' && ch != 'y' ) ch = getchar(); return ( ch == 'x' ? 1 : 0 ); } inline void update( int x , int y ) { for( int i = x ; i <= n ; i += lowbit( i ) ) bit[i] += y; } inline ll get( int x ) { ll sum = 0; for( int i = x ; i ; i -= lowbit( i ) ) sum += bit[i]; return sum; } int main() { n = read() , m = read(); for( int i = 1 , x , y ; i <= m ; i ++ ) { if( opt() ) x = read() , y = read() , update( x , y ); else x = read() , y = read() , printf( "%lld\n" , get(y) - get( x - 1 ) ); } return 0; }

3|0P1637


跑两边树状数组

先正着跑一边算出lower[i],代表1i-1中小于a[i]的数的个数

再倒着跑一遍算出upper[i],代表i+1n中大于a[i]的数的个数

枚举三元中间的一个,1i-1任何一个小于a[i]的都可以做第一个元,i+1n中任何一个大于a[i]的都可以做第三个元

所以答案ans=i=1nloweri×upperi

对于a[i]尽管范围很大但总数很小哈希一下就好

#include <bits/stdc++.h> using namespace std; #define ll long long #define lowbit( x ) ( x & -x ) #define val first #define id second const int N = 3e4 + 5; int n , m , bit[N] , lower[N] , upper[N]; ll a[N] , b[N] , ans; inline ll read() { ll x = 0; char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar(); return x; } inline void update( int x , int y ) { for( int i = x ; i <= m ; i += lowbit( i ) ) bit[i] += y; } inline int get( int x ) { int sum = 0; for( int i = x ; i ; i -= lowbit( i ) ) sum += bit[i]; return sum; } int main() { n = read(); for( int i = 1 ; i <= n ; i ++ ) a[i] = b[i] = read(); sort( b + 1 , b + 1 + n ); m = unique( b + 1 , b + 1 + n ) - b - 1; for( int i = 1 ; i <= n ; i ++ ) a[i] = lower_bound( b + 1 , b + 1 + m , a[i] ) - b; for( int i = 1 ; i <= n ; i ++ ) { lower[i] = get( a[i] - 1 ); update( a[i] , 1 ); } memset( bit , 0 , sizeof( bit ) ); for( int i = n ; i >= 1 ; i -- ) { update( a[i] , 1 ); upper[i] = n - i + 1 - get( a[i] ); } for( int i = 1 ; i <= n ; i ++ ) ans += lower[i] * upper[i]; cout << ans << endl; }

4|0P1276


4|1线段树


可以用线段树来维护所有状态相同的点来降低复杂度,在修改的操作时顺便将一些状态相同的点给合并。

对于线段树的每个节点有四种状态

  • 1 该区间全部是树木
  • 2 该区间全部是树苗
  • 0 该区间全部为坑
  • -1 该区间内部点状态不同

对于查询,没有必要用线段树进行维护,我们只需要在修改的时候统计结果即可

在修改时,如果该区间为-1则递归操作两个子节点,并在操作后考虑吧时候能够合并两个子节点为一个节点

至于从0开始,将所有的点偏移一个单位即可

#include <bits/stdc++.h> using namespace std; const int N = 1e4 + 5; int n , m , ans1 , ans2 ;// ans1 现有多少树苗 , ans2 有多少树苗被砍掉 struct Node { int l , r , value;// 0 没有树 1树木 2 树苗 -1不能当作一个整体 Node * left , * right; Node( int l , int r , int value , Node * left , Node * right ) : l(l) , r(r) , value(value) , left(left) , right(right){}; } * root; inline int read() { register int x = 0 , f = 1 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar(); return x; } inline Node * build( int l , int r ) { if( l == r ) return new Node( l , r , 1 , 0 , 0 ); register int mid = ( l + r ) >> 1; Node * left = build( l , mid ) , * right = build( mid + 1 , r ); return new Node( l , r , 1 , left , right ); } inline void modify_cut( int l , int r , Node * cur ) { register int mid = ( cur -> l + cur -> r ) >> 1; if( cur -> value != -1 && cur -> value != 1 && cur -> left ) cur -> left -> value = cur -> value , cur -> right -> value = cur -> value; if( l <= cur -> l && r >= cur -> r ) { if( cur -> value == 0 ) return ; if( cur -> value == 1 ) cur -> value = 0; if( cur -> value == 2 ) cur -> value = 0 , ans1 -= cur -> r - cur -> l + 1 , ans2 += cur -> r - cur -> l + 1; if( cur -> value == -1 ) cur -> value = 0 , modify_cut( l , r , cur -> left ) , modify_cut( l , r , cur -> right ); } else { if( l <= mid ) modify_cut( l , r , cur -> left ); if( r > mid ) modify_cut( l , r , cur -> right ); if( cur -> left -> value != cur -> right -> value ) cur -> value = -1; else cur -> value = cur -> left -> value; } } inline void modify_plant( int l , int r , Node * cur ) { if( cur -> value != -1 && cur -> value != 1 && cur -> left) cur -> left -> value = cur -> right -> value = cur -> value; if( l <= cur -> l && r >= cur -> r ) { if( cur -> value >= 1 ) return ; if( cur -> value == 0 ) cur -> value = 2 , ans1 += cur -> r - cur -> l + 1; if( cur -> value == -1 ) modify_plant( l , r , cur -> left ) , modify_plant( l , r , cur -> right ); } else { register int mid = ( cur -> l + cur -> r ) >> 1; if( l <= mid ) modify_plant( l , r , cur -> left ); if( r > mid ) modify_plant( l , r , cur -> right ); if( cur -> left -> value != cur -> right -> value ) cur -> value = -1; else cur -> value = cur -> left -> value; } } int main() { n = read() + 1 , m = read(); root = build( 1 , n ); for( register int i = 1 , op , l , r ; i <= m ; i ++ ) { op = read() , l = read() + 1 , r = read() + 1; if( l > r ) swap( l , r ); if( op == 0 ) modify_cut( l , r , root ); else modify_plant( l , r , root ); } cout << ans1 << endl << ans2 << endl; return 0; }

4|2暴力


写完后计算复杂度发现数据太水,暴力模拟都能过,复杂度应该是O(n×L)

#include <bits/stdc++.h> using namespace std; const int N = 1e4 + 5; int n , m , ans1 , ans2 , a[N]; inline int read() { register int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar(); return x; } int main() { n = read() + 1 , m = read(); memset( a , 1 , sizeof(a) ); for( register int i = 1 , op , l , r ; i <= m ; i ++ ) { op = read() , l = read() + 1 , r = read() + 1; if( op == 0 ) { for( register int j = l ; j <= r ; j ++ ) { if( !a[j] ) continue; if( a[j] == 2 ) ans1 -- , ans2 ++; a[j] = 0; } } else { for( register int j = l ; j <= r ; j ++ ) { if( a[j] ) continue; a[j] = 2 , ans1 ++; } } } cout << ans1 << endl << ans2 << endl; return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/15576998.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(35)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示