1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #include<vector> 9 10 using namespace std; 11 12 #define mnx 204000 13 #define ll long long 14 #define inf 0x3f3f3f3f 15 #define lson l, m, rt << 1 16 #define rson m+1, r, rt << 1 | 1 17 18 int sum[mnx<<2], h, w, n;; 19 void pushup( int rt ){ 20 sum[rt] = max( sum[rt<<1], sum[rt<<1|1] ); 21 } 22 void build( int l, int r, int rt ){ 23 if( l == r ){ 24 sum[rt] = w; return ; 25 } 26 int m = ( l + r ) >> 1; 27 build( lson ); 28 build( rson ); 29 pushup( rt ); 30 } 31 int find( int v, int l, int r, int rt ){ 32 int ret; 33 if( l == r ){ 34 if( sum[rt] < v ) ret = -1; 35 else sum[rt] -= v, ret = l; 36 return ret; 37 } 38 int m = ( l + r ) >> 1; 39 if( sum[rt<<1] >= v ){ 40 ret = find( v, lson ); 41 } 42 else ret = find( v, rson ); 43 pushup( rt ); 44 return ret; 45 } 46 int main(){ 47 while( scanf( "%d %d %d", &h, &w, &n ) != EOF ){ 48 h = min( h, n ); 49 build( 1, h, 1 ); 50 int ww; 51 for( int i = 0; i < n; i++ ){ 52 scanf( "%d", &ww ); 53 printf( "%d ", find( ww, 1, h, 1 ) ); 54 } 55 } 56 return 0; 57 }
思路:倒序插入,这样POS的意义就变为找到这么一个位置可以放置这个人, 使得从这个位置往前数共有POS个空位,线段树的节点中cnt表示在[l,r)区间中共有多少 个空位
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #include<vector> 9 10 using namespace std; 11 12 #define mnx 204000 13 #define ll long long 14 #define inf 0x3f3f3f3f 15 #define lson l, m, rt << 1 16 #define rson m+1, r, rt << 1 | 1 17 18 int sum[mnx<<2], pos[mnx], val[mnx], ans[mnx], n; 19 void pushup( int rt ){ 20 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 21 } 22 void build( int l, int r, int rt ){ 23 if( l == r ){ 24 sum[rt] = 1; return ; 25 } 26 int m = ( l + r ) >> 1; 27 build( lson ); 28 build( rson ); 29 pushup( rt ); 30 } 31 void update( int p, int v, int l, int r, int rt ){ 32 if( l == r ){ 33 sum[rt] = 0; 34 ans[l] = v; 35 return ; 36 } 37 int m = ( l + r ) >> 1; 38 if( p <= sum[rt<<1] ) update( p, v, lson ); 39 else update( p - sum[rt<<1], v, rson ); 40 pushup( rt ); 41 } 42 int main(){ 43 while( scanf( "%d", &n ) != EOF ){ 44 for( int i = 0; i < n; i++ ){ 45 scanf( "%d %d", &pos[i], &val[i] ); 46 } 47 build( 1, n, 1 ); 48 for( int i = n - 1; i >= 0; i-- ){ 49 update( pos[i]+1, val[i], 1, n, 1 ); 50 } 51 for( int i = 1; i <= n; i++ ){ 52 printf( "%d%c", ans[i], i == n ? ' ' : ' ' ); 53 } 54 } 55 return 0; 56 }
poj2886 Who Gets the Most Candies?
思路:线段数 反素数(反素数不懂的去问度娘,看博客)。。 先算出N个人中,是第几个人(ans)跳出来得到的糖果最多(用dfs算出)。然后模拟ans遍。。
线段树的结点中保存该区间内还剩多少人,每次update 删除一个人。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #include<vector> 9 10 using namespace std; 11 12 #define mnx 504000 13 #define ll long long 14 #define inf 0x3f3f3f3f 15 #define lson l, m, rt << 1 16 #define rson m+1, r, rt << 1 | 1 17 18 int sum[mnx<<2], n, val[mnx], cnt, best, ans; 19 char ch[mnx][11]; 20 int p[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 21 void pushup( int rt ){ 22 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 23 } 24 void build( int l, int r, int rt ){ 25 if( l == r ){ 26 sum[rt] = 1; 27 return ; 28 } 29 int m = ( l + r ) >> 1; 30 build( lson ); 31 build( rson ); 32 pushup( rt ); 33 } 34 int update( int p, int l, int r, int rt ){ 35 int ret; 36 if( l == r ){ 37 sum[rt] = 0; 38 return l; 39 } 40 int m = ( l + r ) >> 1; 41 if( sum[rt<<1] >= p ) ret = update( p, lson ); 42 else ret = update( p - sum[rt<<1], rson ); 43 pushup( rt ); 44 return ret; 45 } 46 void dfs( int dept, int tmp, int num ){ 47 if( dept >= 16 ) return; 48 if( num > best ){ 49 best = num; 50 ans = tmp; 51 } 52 if( num == best && ans > tmp ) ans = tmp; 53 for( int i = 1; i <= 20; i++ ){ 54 if( n / p[dept] < tmp ) break; 55 dfs( dept + 1, tmp *= p[dept], num * ( i + 1 ) ); 56 } 57 } 58 int main(){ 59 int k; 60 while( scanf( "%d %d", &n, &k ) != EOF ){ 61 ans = inf; 62 best = 0; 63 dfs( 0, 1, 1 ); 64 build( 1, n, 1 ); 65 cnt = 1; 66 for( int i = 1; i <= n; i++ ){ 67 scanf( "%s %d", &ch[i], &val[i] ); 68 } 69 int mod, pre; 70 for( int i = 0; i < ans; i++ ){ 71 pre = k; 72 k = update( k, 1, n, 1 ); 73 if( i == ans-1 ) break; 74 mod = sum[1]; 75 if( val[k] > 0 ){ 76 k = ( pre - 1 + val[k] % mod ) % mod; 77 if( k == 0 ) k = mod; 78 } 79 else{ 80 k = ( mod + pre - ( -val[k] % mod ) ) % mod ; 81 if( k == 0 ) k = mod; 82 } 83 } 84 printf( "%s %d ", ch[k], best ); 85 } 86 return 0; 87 }
http://poj.org/problem?id=3264 Balanced Lineup
线段树作用,区间查询。。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<string> 5 #include<queue> 6 #include<cmath> 7 #include<vector> 8 9 using namespace std; 10 11 #define mnx 50005 12 #define ll long long 13 #define mod 1000000007 14 #define inf 0x3f3f3f3f 15 #define lson l, m, rt << 1 16 #define rson m+1, r, rt << 1 | 1 17 18 int max( int a, int b ){ 19 return a > b ? a : b; 20 } 21 int min( int a, int b ){ 22 return a < b ? a : b; 23 } 24 int max_rt[mnx<<2], min_rt[mnx<<2], ans1, ans2; 25 void build( int l, int r, int rt ){ 26 if( l == r ){ 27 scanf( "%d", &max_rt[rt] ); 28 min_rt[rt] = max_rt[rt]; 29 return ; 30 } 31 int m = ( l + r ) >> 1; 32 build( lson ); build( rson ); 33 max_rt[rt] = max( max_rt[rt<<1], max_rt[rt<<1|1] ); 34 min_rt[rt] = min( min_rt[rt<<1], min_rt[rt<<1|1] ); 35 } 36 void find( int L, int R, int l, int r, int rt ){ 37 if( L <= l && R >= r ){ 38 ans1 = max( ans1, max_rt[rt] ); 39 ans2 = min( ans2, min_rt[rt] ); 40 return ; 41 } 42 int m = ( l + r ) >> 1; 43 if( L <= m ) find( L, R, lson ); 44 if( R > m ) find( L, R, rson ); 45 } 46 int main(){ 47 int n, q; 48 while( scanf( "%d %d", &n, &q ) != EOF ){ 49 build( 1, n, 1 ); 50 while( q-- ){ 51 int l, r; 52 ans1 = 0, ans2 = inf; 53 scanf( "%d %d", &l, &r); 54 find( l, r, 1, n, 1 ); 55 printf( "%d ", ans1 - ans2 ); 56 } 57 } 58 return 0; 59 }
ZOJ 3772 Calculate the Function
思路:首先,对于形如f(x) = p * f(x-1) + q * f(x-2)的通项都可以转成矩阵乘法。。
f(x)=f(x-1) + a[x]* f(x-2), 所以就有递推式
所以当r>=l+1时,
然后就可以先求出:
用线段树就可以在O(logn)的时间求出这个式子,不过线段树的每个节点保存的是一个矩阵
还有就是要注意矩阵乘的方向
总的复杂度是O(nlogn+mlogn),线段树作用 区间查询
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<string> 6 #include<queue> 7 #include<cmath> 8 #include<vector> 9 10 using namespace std; 11 12 #define mnx 104000 13 #define ll long long 14 #define mod 1000000007 15 #define inf 0x3f3f3f3f 16 #define lson l, m, rt << 1 17 #define rson m+1, r, rt << 1 | 1 18 19 ll b[mnx]; 20 struct mat{ 21 ll a[2][2]; 22 mat(){ 23 memset( a, 0, sizeof(a) ); 24 } 25 mat( ll x ){ 26 a[0][0] = 1, a[1][0] = 1; 27 a[0][1] = x, a[1][1] = 0; 28 } 29 mat operator * ( const mat & b ) const{ 30 mat ret; 31 for( int i = 0; i < 2; i++ ) 32 for( int j = 0; j < 2; j++ ) 33 for( int k = 0; k < 2; k++ ) 34 ret.a[i][j] = ( ret.a[i][j] + a[i][k] * b.a[k][j] ) % mod; 35 return ret; 36 } 37 }sum[mnx<<2]; 38 void build( int l, int r, int rt ){ 39 if( l == r ){ 40 sum[rt] = mat( b[l] ); 41 return ; 42 } 43 int m = ( l + r ) >> 1; 44 build( lson ); 45 build( rson ); 46 sum[rt] = sum[rt<<1|1] * sum[rt<<1]; 47 } 48 mat find( int L, int R, int l, int r, int rt ){ 49 mat ret; 50 ret.a[0][0] = ret.a[1][1] = 1, ret.a[1][0] = ret.a[0][1] = 0; 51 if( L <= l && R >= r ){ 52 return sum[rt]; 53 } 54 int m = ( l + r ) >> 1; 55 if( R > m ) ret = ret * find( L, R, rson ); 56 if( L <= m ) ret = ret * find( L, R, lson ); 57 return ret; 58 } 59 int main(){ 60 int cas; 61 scanf( "%d", &cas ); 62 while( cas-- ){ 63 int n, m; 64 scanf( "%d %d", &n, &m ); 65 for( int i = 1; i <= n; i++ ){ 66 scanf( "%lld", &b[i] ); 67 } 68 build( 1, n, 1 ); 69 while( m-- ){ 70 int l, r; 71 scanf( "%d %d", &l, &r ); 72 if( l == r || l + 1 == r ){ 73 printf( "%lld ", b[r] ); 74 } 75 else{ 76 mat ans = find( l + 2, r, 1, n, 1 ), q; 77 q.a[0][0] = b[l+1], q.a[1][0] = b[l], q.a[0][1] = q.a[1][1] = 0; 78 ans = ans * q; 79 printf( "%lld ", ans.a[0][0] ); 80 } 81 } 82 } 83 return 0; 84 }
hdu4027 Can you answer these queries?
看起来好像要区间更新,但实际上是单点更新。。每个叶子节点进行开根号,进行几次开方之后就变成了1,以后就不用在开方了。。用一个vis[]数组对每个节点进行标记,如果vis[] = true,就说明该区间的所有节点都是1,就不用进行开根号。。叶子节点是1的话,vis[rt] = true;其他节点就看左右儿子,if( vis[rt<<1] && vis[rt<<1|1] ) vis[rt] = true;
这道题还有一个特别坑爹的地方:就是输入的要操作的区间,x不一定小于y,所以如果x>y的话,就要swap( x, y );
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<string> 6 #include<cmath> 7 #include<map> 8 #include<queue> 9 10 using namespace std; 11 12 #define mnx 200005 13 #define Pi acos(-1.0) 14 #define ull unsigned long long 15 #define ll long long 16 #define inf 0x3f3f3f3f 17 #define eps 1e-8 18 #define MP make_pair 19 #define lson l, m, rt << 1 20 #define rson m+1, r, rt << 1 | 1 21 #define mod 2333333 22 23 ll sum[mnx<<2]; 24 bool vis[mnx<<2]; 25 void pushup( int rt ){ 26 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 27 if( vis[rt<<1] && vis[rt<<1|1] ) vis[rt] = 1; 28 } 29 void build( int l, int r, int rt ){ 30 if( l == r ){ 31 scanf( "%I64d", &sum[rt] ); 32 if( sum[rt] == 1 ) vis[rt] = 1; 33 return ; 34 } 35 int m = ( l + r ) >> 1; 36 build( lson ); 37 build( rson ); 38 pushup( rt ); 39 } 40 ll query( int L, int R, int l, int r, int rt ){ 41 if( L <= l && R >= r ){ 42 return sum[rt]; 43 } 44 ll ret = 0, m = ( l + r ) >> 1; 45 if( L <= m ) ret += query( L, R, lson ); 46 if( R > m ) ret += query( L, R, rson ); 47 return ret; 48 } 49 void update( int L, int R, int l, int r, int rt ){ 50 if( vis[rt] ) return; 51 if( l == r && L <= l && R >= r ){ 52 sum[rt] = sqrt( sum[rt] - 0.0 ); 53 if( sum[rt] == 1 ) vis[rt] = 1; 54 return ; 55 } 56 int m = ( l + r ) >> 1; 57 if( L <= m ) update( L, R, lson ); 58 if( R > m ) update( L, R, rson ); 59 pushup( rt ); 60 } 61 int main(){ 62 int n, m, cnt = 1, op; 63 while( scanf( "%d", &n ) != EOF ){ 64 memset( vis, 0, sizeof(vis) ); 65 build( 1, n, 1 ); 66 scanf( "%d", &m ); 67 printf( "Case #%d: ", cnt++ ); 68 int l, r; 69 while( m-- ){ 70 scanf( "%d %d %d", &op, &l, &r ); 71 if( l > r ) swap( l, r ); 72 if( op == 1 ){ 73 printf( "%I64d ", query( l, r, 1, n, 1 ) ); 74 } 75 if( op == 0 ){ 76 update( l, r, 1, n, 1 ); 77 } 78 } 79 puts( "" ); 80 } 81 return 0; 82 }
给你n个数,有两种操作,一个是把第 u 个数的值变为 v, 第二种操作是问你 u-v这个区间内所有数相乘的乘积是'+' or '-' or '0',输出符号就好;
把负数变为-1,把正数变为1,这样就不会相乘溢出了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #include<queue> 8 9 using namespace std; 10 11 #define inf 1e16 12 #define eps 1e-6 13 #define LL long long 14 #define ULL unsigned long long 15 #define MP make_pair 16 #define pb push_back 17 #define lson l, m, rt<<1 18 #define rson m+1, r, rt<<1|1 19 #define mnx 100500 20 21 int a[mnx], sum[mnx<<2]; 22 void pushup( int rt ){ 23 sum[rt] = sum[rt<<1] * sum[rt<<1|1]; 24 } 25 void build( int l, int r, int rt ){ 26 if( l == r ){ 27 sum[rt] = a[l]; 28 return ; 29 } 30 int m = ( l + r ) >> 1; 31 build( lson ); 32 build( rson ); 33 pushup( rt ); 34 } 35 void update( int u, int v, int l, int r, int rt ){ 36 if( l == r ){ 37 if( v > 0 ) sum[rt] = 1; 38 else if( v == 0 ) sum[rt] = 0; 39 else sum[rt] = -1; 40 return ; 41 } 42 int m = ( l + r ) >> 1; 43 if( u <= m ) update( u, v, lson ); 44 if( u > m ) update( u, v, rson ); 45 pushup( rt ); 46 } 47 int query( int L, int R, int l, int r, int rt ){ 48 if( L <= l && R >= r ) 49 return sum[rt]; 50 int ret = 1, m = ( l + r ) >> 1; 51 if( L <= m ) ret *= query( L, R, lson ); 52 if( R > m ) ret *= query( L, R, rson ); 53 return ret; 54 } 55 int main(){ 56 //freopen( "tt.txt", "r", stdin ); 57 int n, m; 58 while( scanf( "%d%d", &n, &m ) != EOF ){ 59 for( int i = 1; i <= n; ++i ){ 60 scanf( "%d", &a[i] ); 61 if( a[i] > 0 ) a[i] = 1; 62 else if( a[i] == 0 ) a[i] = 0; 63 else a[i] = -1; 64 } 65 build( 1, n, 1 ); 66 while( m -- ){ 67 char s[3]; 68 int u, v; 69 scanf( "%s%d%d", s, &u, &v ); 70 if( s[0] == 'C' ) update( u, v, 1, n, 1 ); 71 else{ 72 int ok = query( u, v, 1, n, 1 ); 73 if( ok == 1 ) printf( "+" ); 74 else if( ok == 0 ) printf( "0" ); 75 else printf( "-" ); 76 } 77 } 78 puts( "" ); 79 } 80 return 0; 81 }