线段树 单点更新,区间查询

hdu2795 Billboard

 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\n", find( ww, 1, h, 1 ) );
54         }
55     }
56     return 0;
57 }
View Code

poj2828 Buy Tickets

思路:倒序插入,这样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 ? '\n' : ' ' );
53         }
54     }
55     return 0;
56 }
View Code

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\n", ch[k], best );
85     }
86     return 0;
87 }
View Code

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\n", ans1 - ans2 );
56         }
57     }
58     return 0;
59 }
View Code

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\n", 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\n", ans.a[0][0] );
80             }
81         }
82     }
83     return 0;
84 }
View Code

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:\n", 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\n", 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 }
View Code

 UVA 12532 Interval Product

给你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 }
View Code

 

转载于:https://www.cnblogs.com/LJ-blog/p/3909681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值