线段树|树状数组|RMQ

能用树状数组的都能用线段树,但是树状数组写法简单
K & (-K) 是用来取最右边的1 (一个数求补,那么最右边的1不会改变)
在这里插入图片描述

HDU - 1166 题目链接

树状数组模板题,单点更新,区间查询

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int N = 5e4 + 5;
int n;
int tree[N];
int lowbit(int k)
{
    return k & (-k);
}
void update(int x,int k)
{
    while(x <= n){
        tree[x] += k;
        x += lowbit(x);
    }
}
int getsum(int x)
{
    int ans = 0;
    while(x){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    int t,Case = 1;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(tree,0,sizeof(tree));
        for (int i = 1; i <= n; i++){
            int x;
            scanf("%d",&x);
            update(i,x);
        }
        string s;
        printf("Case %d:\n",Case++);
        while(cin >> s && s != "End"){
            if (s == "Add"){
                int x,v;
                scanf("%d %d",&x,&v);
                update(x,v);
            }
            if (s == "Sub"){
                int x,v;
                scanf("%d %d",&x,&v);
                update(x,-v);
            }
            if (s == "Query"){
                int a,b;
                scanf("%d %d",&a,&b);
                printf("%d\n",getsum(b) - getsum(a - 1));
            }
        }
    }
    return 0;
}

HDU - 1556 题目链接

区间更新,单点查询,树状数组写法

利用差分的性质进行更新
A[] = 1 2 3 5 6 9
D[] = 1 1 1 2 1 3
D【1,i】区间的和就是 a[i] 的值
如果我们把[2,5]区间内值加上2,则变成了
A[] = 1 4 5 7 8 9
D[] = 1 3 1 2 1 1
也就是只更新了 ,D【2】+ 2,D【5】 - 2;(因为树状数组是更新 【x,n】这个区间,所以我们要更新【2,5】,那就相当于更新了【2,n】+ 2 和 【5,n】- 2

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int tree[N];
int n;
int lowbit(int k)
{
    return k & (-k);
}
void updata(int x,int k)
{
    while(x <= n){
        tree[x] += k;
        x += lowbit(x);
    }
}
int query(int x)
{
    int ans = 0;
    while(x){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    while(scanf("%d",&n) == 1 && n){
        memset(tree,0,sizeof(tree));
        for (int i = 0; i < n; i++){
            int a,b;
            scanf("%d %d",&a,&b);
            updata(a,1);
            updata(b + 1,-1);
        }
        for (int i = 1; i < n; i++){
            printf("%d ",query(i));
        }
        printf("%d\n",query(n));
    }
    return 0;
}

线段树写法

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int tree[4 * N];
int lazy[4 * N];
void build(int L,int R,int rt)
{
    if (L == R){
        tree[rt] = 0;
        return ;
    }
    int mid = (L + R) >> 1;
    build(L,mid,rt << 1);
    build(mid + 1,R,rt << 1 | 1);
}
void push_down(int id)
{
    tree[id << 1] += lazy[id];
    tree[id << 1 | 1] += lazy[id];
    lazy[id << 1] += lazy[id];
    lazy[id << 1 | 1] += lazy[id];
    lazy[id] = 0;
}
void updata(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b){
        lazy[id] += 1;
        tree[id] += 1;
        return ;
    }
    int mid = (l + r) >> 1;
    if (a <= mid) updata(a,b,l,mid,id << 1);
    if (b > mid) updata(a,b,mid + 1,r,id << 1 | 1);
}
int query(int pos,int l,int r,int id)
{
    if (l == r) return tree[id];
    if (lazy[id]) push_down(id);
    int mid = (l + r) >> 1;
    if (pos <= mid) query(pos,l,mid,id << 1);
    else query(pos,mid + 1,r,id << 1 | 1);
}
int main()
{
    int n;
    while(scanf("%d",&n) == 1 && n){
        memset(lazy,0,sizeof(lazy));
        build(1,n,1);
        for (int i = 0; i < n; i++){
            int a,b;
            scanf("%d %d",&a,&b);
            updata(a,b,1,n,1);
        }
        for (int i = 1; i < n; i++){
            printf("%d ",query(i,1,n,1));
        }
        printf("%d\n",query(n,1,n,1));
    }
    return 0;
}

POJ - 2155 题目链接

这题就是HDU1556的升级版,就是从一维变成二维矩阵
每次改变就是变成0变1,或者1变0,所以我们记录改变的次数,然后结果 mod 2即可
更新矩阵的原理也是类似
【x1 ~ n,y1 ~ n】【x2 + 1 ~ n,y1 ~ n】【x1 ~ n,y2 + 1 ~ n】【x2 + 1~n,y2 + 1 ~ n】
图上的数字代表更新次数,偶数就相当于没更新

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1111;
int tree[N][N];
int n,q;
int lowbit(int k)
{
    return k & (-k);
}
void updata(int x,int y)
{
    for (int i = x; i <= n; i += lowbit(i)){
        for (int j = y; j <= n; j += lowbit(j)){
            tree[i][j]++;
        }
    }
}
int query(int x,int y)
{
    int ans = 0;
    for (int i = x; i > 0; i -= lowbit(i)){
        for (int j = y; j > 0; j -= lowbit(j)){
            ans += tree[i][j];
        }
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&q);
        memset(tree,0,sizeof(tree));
        for (int i = 0; i < q; i++){
            char c;
            scanf(" %c",&c);
            if (c == 'C'){
                int x1,y1,x3,y3;
                scanf("%d %d %d %d",&x1,&y1,&x3,&y3);
                updata(x1,y1);
                updata(x3 + 1,y1);
                updata(x1,y3 + 1);
                updata(x3 + 1,y3 + 1);
            }
            else {
                int x,y;
                scanf("%d %d",&x,&y);
                printf("%d\n",query(x,y) & 1);
            }
        }
        printf("\n");
    }
    return 0;
}

POJ - 2299 题目链接

逆序数模板题

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N = 5e5 + 6;
typedef long long ll;
struct node{
    int x,v;
    bool operator < (const node &p) const{
        if (v == p.v) return x < p.x;
        return v < p.v;
    }
}s[N];
int a[N],n,tree[N];
int lowbit(int k)
{
    return k & (-k);
}
void update(int x)
{
    while(x <= n){
        tree[x]++;
        x += lowbit(x);
    }
}
int getsum(int x)
{
    int ans = 0;
    while(x){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    while(scanf("%d",&n) == 1 && n){
        memset(tree,0,sizeof(tree));
        for (int i = 1; i <= n; i++){
            scanf("%d",&s[i].v);
            s[i].x = i;
        }
        sort(s + 1,s + 1 + n);
        for (int i = 1; i <= n; i++){
            a[s[i].x] = i;
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++){
            update(a[i]);
            ans += i - getsum(a[i]);
        }
        cout << ans << endl;
    }
    return 0;
}

POJ - 3067 题目链接

先把左边的排好序,那么每连接一条边增加的权值就等于v(大于b的值)
v = i - sum(b)(sum[b]代表[1,b]的和)
在这里插入图片描述

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1111;
typedef long long ll;
struct node{
    int a,b;
    bool operator < (const node &p) const{
        if (a == p.a) return b < p.b;
        return a < p.a;
    }
}s[N * N];
int tree[N];
int lowbit(int k)
{
    return k & (-k);
}
void update(int x)
{
    while(x <= N){
        tree[x]++;
        x += lowbit(x);
    }
}
int getsum(int x)
{
    int ans = 0;
    while(x){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    int t,Case = 1;
    scanf("%d",&t);
    while(t--){
        int n,m,k;
        scanf("%d %d %d",&n,&m,&k);
        for (int i = 0; i < k; i++){
            scanf("%d %d",&s[i].a,&s[i].b);
        }
        sort(s,s + k);
        memset(tree,0,sizeof(tree));
        ll ans = 0;
        for (int i = 0; i < k; i++){
            ans += i - getsum(s[i].b);
            update(s[i].b);
        }
        printf("Test case %d: %I64d\n",Case++,ans);
    }
    return 0;
}

HDU - 1754 题目链接

线段树求区间最大值

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int tree[4 * N];
void build(int L,int R,int rt)
{
    if (L == R){
        scanf("%d",&tree[rt]);
        return ;
    }
    int mid = (L + R) >> 1;
    build(L,mid,rt << 1);
    build(mid + 1,R,rt << 1 | 1);
    tree[rt] = max(tree[rt << 1],tree[rt << 1 | 1]);
}
void updata(int pos,int x,int L,int R,int rt)
{
    if (L == R){
        tree[rt] = x;
        return ;
    }
    int mid = (L + R) >> 1;
    if (pos <= mid) updata(pos,x,L,mid,rt << 1);
    if (pos > mid) updata(pos,x,mid + 1,R,rt << 1 | 1);
    tree[rt] = max(tree[rt << 1],tree[rt << 1 | 1]);
}
int query(int a,int b,int L,int R,int rt)
{
    if (a <= L && R <= b)   return tree[rt];
    int mid = (L + R) >> 1;
    int ans = -1;
    if (a <= mid)   ans = max(ans,query(a,b,L,mid,rt << 1));
    if (b > mid)    ans = max(ans,query(a,b,mid + 1,R,rt << 1 | 1));
    return ans;
}
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m) == 2){
        build(1,n,1);
        char c;
        int a,b;
        for (int i = 0; i < m; i++){
            scanf(" %c %d %d",&c,&a,&b);
            if (c == 'Q'){
                printf("%d\n",query(a,b,1,n,1));
            }
            else {
                updata(a,b,1,n,1);
            }
        }
    }
    return 0;
}

POJ - 3468 题目链接

注意 long long
线段树区间更新,区间查询

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
ll tree[4 * N],lazy[4 * N];
void build(int l,int r,int rt)
{
    if (l == r){
        scanf("%I64d",&tree[rt]);
        return ;
    }
    int mid = (l + r) >> 1;
    build(l,mid,rt << 1);
    build(mid + 1,r,rt << 1 | 1);
    tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
void push_down(int id,int len)
{
	//顺序不能颠倒
    tree[id << 1] += lazy[id] * (len - (len >> 1));
    tree[id << 1 | 1] += lazy[id] * (len >> 1);
    lazy[id << 1] += lazy[id];
    lazy[id << 1 | 1] += lazy[id];
    lazy[id] = 0;
}
void updata(int a,int b,int x,int l,int r,int id)
{
    if (a <= l && r <= b){
        lazy[id] += x;
        tree[id] += x * (r - l + 1);
        return ;
    }
    if (lazy[id]) push_down(id,r - l + 1);
    int mid = (l + r) >> 1;
    if (a <= mid) updata(a,b,x,l,mid,id << 1);
    if (b > mid) updata(a,b,x,mid + 1,r,id << 1 | 1);
    tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
ll query(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b)   return tree[id];
    if (lazy[id]) push_down(id,r - l + 1);
    int mid = (l + r) >> 1;
    ll ans = 0;
    if (a <= mid)   ans += query(a,b,l,mid,id << 1);
    if (b > mid)    ans += query(a,b,mid + 1,r,id << 1 | 1);
    tree[id] = tree[id << 1] + tree[id << 1 | 1];
    return ans;
}
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m) == 2){
        build(1,n,1);
        char c;
        int a,b,x;
        memset(lazy,0,sizeof(lazy));
        for (int i = 0; i < m; i++){
            scanf(" %c",&c);
            if (c == 'Q'){
                scanf("%d %d",&a,&b);
                printf("%I64d\n",query(a,b,1,n,1));
            }
            else {
                scanf("%d %d %d",&a,&b,&x);
                updata(a,b,x,1,n,1);
            }
        }
    }
    return 0;
}

POJ - 3264 题目链接

区间查询最值,不进行更新,可以使用

更新

RMQ:区间从2-4-8-16 ~ 开始转移

dp[i][j] 表示从下标为i开始,长度为2j的区间
dp[i][j] = min(dp [i][j - 1], dp [i + (1 << (j - 1))][j - 1])

查询:

令k = log ⁡ 2 ( r − l + 1 ) \log_2({r - l + 1}) log2(rl+1) , 则区间[l, r]的最小值RMQ[l,r] = min(dp[l][k], dp[r - (1 << k) + 1][k]);
dp[l][k]维护的是区间 [l, l + 2^k - 1] , dp[r - (1 << k) + 1][k]维护的是区间 [r - 2^k + 1, r] 。
那么只要我们保证 r - (1 << k) + 1 ≤ l + 2^k - 1就能保证RMQ[l,r] = min(dp[l][k], dp[r - (1 << k) + 1][k]);
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 5e4 + 5;
int mx[N][20],mi[N][20];
int a[N];
void init_max()
{
    for (int j = 1; (1 << j) <= N; j++){
        /// i + (1 << j) - 1   下标为i长度为(1<<j) 不能超过N
        for (int i = 1; i + (1 << j) - 1 <= N; i++){
            mx[i][j] = max(mx[i][j - 1],mx[i + (1 << (j - 1))][j - 1]);
        }
    }
}
void init_min()
{
    for (int j = 1; (1 << j) <= N; j++){
        for (int i = 1; i + (1 << j) - 1 <= N; i++){
            mi[i][j] = min(mi[i][j - 1],mi[i + (1 << (j - 1))][j - 1]);
        }
    }
}
int query_max(int l,int r)
{
    int k = log2(r - l + 1);
    return max(mx[l][k],mx[r - (1 << k) + 1][k]);
}
int query_min(int l,int r)
{
    int k = log2(r - l + 1);
    return min(mi[l][k],mi[r - (1 << k) + 1][k]);
}
int main()
{
    int n,m;
    while (scanf("%d %d",&n,&m) == 2){
        memset(mx,0,sizeof(mx));
        memset(mi,0,sizeof(mi));
        for (int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
            mx[i][0] = mi[i][0] = a[i];
        }
        init_max();
        init_min();
        for (int i = 0; i < m; i++){
            int x,y;
            scanf("%d %d",&x,&y);
            printf("%d\n",query_max(x,y) - query_min(x,y));
        }
    }
    return 0;
}

HDU - 4027 题目链接

最开始的时候是单点更新平方根,当更新到

tree[id] == r - l + 1时,说明该区间里的数都等于1,那就不用更新了
输入的X可能会大于Y
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
ll tree[4 * N];
void build(int l,int r,int id)
{
    if (l == r){
        scanf("%I64d",&tree[id]);
        return ;
    }
    int mid = (l + r) >> 1;
    build(l,mid,id << 1);
    build(mid + 1,r,id << 1 | 1);
    tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
void updata(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b && tree[id] == r - l + 1) return;
    if (l == r){
        tree[id] = sqrt(tree[id]);
        return ;
    }
    int mid = (l + r) >> 1;
    if (a <= mid) updata(a,b,l,mid,id << 1);
    if (b > mid) updata(a,b,mid + 1,r,id << 1 | 1);
    tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
ll query(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b)   return tree[id];
    int mid = (l + r) >> 1;
    ll ans = 0;
    if (a <= mid)   ans += query(a,b,l,mid,id << 1);
    if (b > mid)    ans += query(a,b,mid + 1,r,id << 1 | 1);
    return ans;
}
int main()
{
    int n,Case = 1;
    while(scanf("%d",&n) == 1){
        printf("Case #%d:\n",Case++);
        build(1,n,1);
        int q;
        scanf("%d",&q);
        for (int i = 0; i < q; i++){
            int op,x,y;
            scanf("%d %d %d",&op,&x,&y);
            if (x > y) swap(x,y);
            if (op == 0){
                updata(x,y,1,n,1);
            }
            else {
                printf("%I64d\n",query(x,y,1,n,1));
            }
        }
        printf("\n");
    }
    return 0;
}

POJ - 2528 题目链接

离散化加区间更新,区间查询

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int a[N * 4],l[N],r[N];
int vis[4 * N],color[N * 16];
void push_down(int id)
{
    color[id << 1] = color[id << 1 | 1] = color[id];
    color[id] = 0;
}
void update(int a,int b,int x,int l,int r,int id)
{
    if (a <= l && r <= b){
        color[id] = x;
        return ;
    }
    if (color[id]) push_down(id);
    int mid = (l + r) >> 1;
    if (a <= mid) update(a,b,x,l,mid,id << 1);
    if (b > mid) update(a,b,x,mid + 1,r,id << 1 | 1);
}
int query(int a,int b,int l,int r,int id)
{
    //cout << "l = " << l << " r = " << r << endl;
    if (color[id]){
        if (!vis[color[id]]){
            vis[color[id]] = 1;
            return 1;
        }
    }
    if (l == r) return 0;
    if (color[id]) push_down(id);
    int mid = (l + r) >> 1;
    int ans = 0;
    if (a <= mid) ans += query(a,b,l,mid,id << 1);
    if (b > mid) ans += query(a,b,mid + 1,r,id << 1 | 1);
    return ans;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
        int n;
        scanf("%d",&n);
        int cnt = 1;
        for (int i = 0; i < n; i++){
            scanf("%d %d",&l[i],&r[i]);
            a[cnt++] = l[i];
            a[cnt++] = r[i];
        }
        sort(a + 1,a + cnt);
        int cnt2 = cnt;
        /// 避免出现 12 24 45 离散后成 12 23 34 覆盖 23的情况
        for (int i = 2; i < cnt; i++){
            if (a[i] - a[i - 1] > 1){
                a[cnt2++] = a[i - 1] + 1;
            }
        }
        sort(a + 1,a + cnt2);
        int num = 2;
        for (int i = 2; i < cnt2; i++){
            if (a[i] != a[i - 1]){
                a[num++] = a[i];
            }
        }
        memset(vis,0,sizeof(vis));
        memset(color,0,sizeof(color));
        for (int i = 0; i < n; i++){
            int x = lower_bound(a,a + num,l[i]) - a;
            int y = lower_bound(a,a + num,r[i]) - a;
         //   cout << "x = " << x << " y = " << y << endl;
            update(x,y,i + 1,1,num - 1,1);
        }
        printf("%d\n",query(1,num - 1,1,num - 1,1));
	}
	return 0;
}

HDU - 1540 题目链接

D x 摧毁x位置
R 复原最近摧毁的位置
Q x 查询与x连接的有多少个村庄

Q (x) = min(x,n) - max(1,x)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int mx[N << 2],mi[N << 2],n,m;
void build(int l,int r,int id)
{
    if (l == r){
        mi[id] = n + 1;
        mx[id] = 0;
        return ;
    }
    int mid = (l + r) >> 1;
    build(l,mid,id << 1);
    build(mid + 1,r,id << 1 | 1);
    mx[id] = max(mx[id << 1],mx[id << 1 | 1]);
    mi[id] = min(mi[id << 1],mi[id << 1 | 1]);
}
void update_max(int pos,int x,int l,int r,int id)
{
    if (l == r){
        mx[id] = x;
        return ;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) update_max(pos,x,l,mid,id << 1);
    if (pos > mid) update_max(pos,x,mid + 1,r,id << 1 | 1);
    mx[id] = max(mx[id << 1],mx[id << 1 | 1]);
}
void update_min(int pos,int x,int l,int r,int id)
{
    if (l == r){
        mi[id] = x;
        return ;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) update_min(pos,x,l,mid,id << 1);
    if (pos > mid) update_min(pos,x,mid + 1,r,id << 1 | 1);
    mi[id] = min(mi[id << 1],mi[id << 1 | 1]);
}
int query_max(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b) return mx[id];
    int mid = (l + r) >> 1;
    int ans = 0;
    if (a <= mid) ans = max(ans,query_max(a,b,l,mid,id << 1));
    if (b > mid) ans = max(ans,query_max(a,b,mid + 1,r,id << 1 | 1));
   // cout << "max = " << ans << endl;
    return ans;
}
int query_min(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b) return mi[id];
    int mid = (l + r) >> 1;
    int ans = INF;
    if (a <= mid) ans = min(ans,query_min(a,b,l,mid,id << 1));
    if (b > mid) ans = min(ans,query_min(a,b,mid + 1,r,id << 1 | 1));
   // cout << "min = " << ans << endl;
    return ans;
}
int main()
{
	while(scanf("%d %d",&n,&m) == 2){
        char ch;
        int x;
        stack<int> st;
        build(1,n,1);
        for (int i = 0; i < m; i++){
            scanf(" %c",&ch);
            if (ch == 'D'){
                scanf("%d",&x);
                st.push(x);
                update_max(x,x,1,n,1);
                update_min(x,x,1,n,1);
            }
            else if (ch == 'R'){
                x = st.top();
                st.pop();
                update_max(x,0,1,n,1);
                update_min(x,n + 1,1,n,1);
            }
            else {
                scanf("%d",&x);
                int r = query_min(x,n,1,n,1);
                int l = query_max(1,x,1,n,1);
               // cout << "l = " << l << " r = " << r << endl;
                if (l == r) cout << 0 << endl;
                else cout << r - l - 1 << endl;
            }
        }
	}
	return 0;
}

HDU - 3974 题目链接

根据雇佣关系,生成线段树,每一个人都用一个区间表示,区间包含关系就表示雇佣关系

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
struct node{
    int to,nex;
}e[N];
int head[N],vis[N],lazy[N << 2],tree[N << 2];
int cnt,num,l[N],r[N];
void add(int u,int v)
{
    e[cnt].to = v;
    e[cnt].nex = head[u];
    head[u] = cnt++;
}
void dfs(int u)
{
    l[u] = ++num;
    for (int i = head[u]; i != -1; i = e[i].nex){
        dfs(e[i].to);
    }
    r[u] = num;
}
void build(int l,int r,int id)
{
    if (l == r){
        tree[id] = lazy[id] = -1;
        return;
    }
    int mid = (l + r) >> 1;
    build(l,mid,id << 1);
    build(mid + 1,r,id << 1 | 1);
    tree[id] = lazy[id] = -1;
}
void push_down(int id)
{
    lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
    tree[id << 1] = tree[id << 1 | 1] = lazy[id];
    lazy[id] = -1;
}
void update(int a,int b,int x,int l,int r,int id)
{
    if (a <= l && r <= b){
        lazy[id] = x;
        tree[id] = x;
        return ;
    }
    if (lazy[id] != -1) push_down(id);
    int mid = (l + r) >> 1;
    if (a <= mid) update(a,b,x,l,mid,id << 1);
    if (b > mid) update(a,b,x,mid + 1,r,id << 1 | 1);
}
int query(int a,int l,int r,int id)
{
    if (l == r) return tree[id];
    if (lazy[id] != -1) push_down(id);
    int mid = (l + r) >> 1;
    int ans;
    if (a <= mid) ans = query(a,l,mid,id << 1);
    if (a > mid) ans = query(a,mid + 1,r,id << 1 | 1);
    return ans;
}
int main()
{
    int t,Case = 1;
    scanf("%d",&t);
    while (t--){
        int n;
        scanf("%d",&n);
        memset(vis,0,sizeof(vis));
        memset(head,-1,sizeof(head));
        cnt = 0;
        for (int i = 1; i < n; i++){
            int u,v;
            scanf("%d %d",&u,&v);
            vis[u]++;
            add(v,u);
        }
        int root;
        for (int i = 1; i <= n; i++){
            if (!vis[i]){
                root = i;
                break;
            }
        }
        num = 0;
        dfs(root);
        build(1,num,1);
        /*
        for (int i = 0; i < n; i++){
            printf("%d %d\n",l[i + 1],r[i + 1]);
        }*/
        int m;
        scanf("%d",&m);
        char ch;
        int x,y;
        printf("Case #%d:\n",Case++);
        for (int i = 0; i < m; i++){
            scanf(" %c",&ch);
            if (ch == 'T'){
                scanf("%d %d",&x,&y);
                update(l[x],r[x],y,1,num,1);
            }
            else {
                scanf("%d",&x);
                printf("%d\n",query(l[x],1,num,1));
            }
        }
    }
	return 0;
}

HDU - 4614 题目链接

二分查找更新区间的左右端点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n,m;
int lazy[N << 2],tree[N << 2];
void push_down(int id,int len)
{
    lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
    tree[id << 1] = lazy[id] * (len - (len >> 1));
    tree[id << 1 | 1] = lazy[id] * (len >> 1);
    lazy[id] = -1;
}
void update(int a,int b,int x,int l,int r,int id)
{
    if (a <= l && r <= b){
        lazy[id] = x;
        tree[id] = x * (r - l + 1);
        return ;
    }
    if (lazy[id] != -1) push_down(id,r - l + 1);
    int mid = (l + r) >> 1;
    if (a <= mid) update(a,b,x,l,mid,id << 1);
    if (b > mid) update(a,b,x,mid + 1,r,id << 1 | 1);
    tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
int query(int a,int b,int l,int r,int id)
{
    if (a <= l && r <= b) return tree[id];
    if (lazy[id] != -1) push_down(id,r - l + 1);
    int mid = (l + r) >> 1;
    int ans = 0;
    if (a <= mid) ans += query(a,b,l,mid,id << 1);
    if (b > mid) ans += query(a,b,mid + 1,r,id << 1 | 1);
    return ans;
}
int binary(int x,int num)
{
    int l = x, r = n,ans = -1;
    while (l <= r){
        int mid = (l + r) >> 1;
        int tem = query(x,mid,1,n,1);
        if (tem + num == mid - x + 1){
            ans = mid;
            r = mid - 1;
        }
        else if (tem + num > mid - x + 1) l = mid + 1;
        else r = mid - 1;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--){
        scanf("%d %d",&n,&m);
        memset(tree,0,sizeof(tree));
        memset(lazy,-1,sizeof(lazy));
        for (int i = 0; i < m; i++){
            int op,x,y;
            scanf("%d %d %d",&op,&x,&y);
            x++;
            if (op == 1){
                int st = binary(x,1);
                if (st == -1) printf("Can not put any one.\n");
                else {
                    int tem = n - x + 1 - query(x,n,1,n,1);
                    if (tem <= y) y = tem;
                    int ed = binary(x,y);
                    printf("%d %d\n",st - 1,ed - 1);
                    update(st,ed,1,1,n,1);
                }
            }
            else{
                y++;
                printf("%d\n",query(x,y,1,n,1));
                update(x,y,0,1,n,1);
            }
        }
        printf("\n");
    }
	return 0;
}

HDU - 4578 题目链接

三重标记
定义标记的优先级  same > mult > add
如果同一层中三种标记都有,说明mult标记和add标记都是后来出现的(如果是前面已有的,那么根据优先级
same标记会清除这两个标记)
使用mult下放标记时,下放那一层如果有add标记,那么说明add标记是已经存在的,所以计算过程为
(原数 + add) * mult = (原数) * mult + add * mult (add为0,就说明没有标记,不影响结果)
mult 操作:a、b、c为原数,d为mult标记   (mult标记默认值为1)

( a d ) + ( b d ) + ( c d ) = = ( a + b + c ) ∗ d (ad) + (bd) + (cd) == ({a} + {b} + {c}) * {d} (ad)+(bd)+(cd)==(a+b+c)d

( a d ) 2 + ( b d ) 2 + ( c d ) 2 = = ( a 2 + b 2 + c 2 ) ∗ d 2 (ad)^2 + (bd)^2 + (cd)^2 == ({a^2} + {b^2} + {c^2}) * {d^2} (ad)2+(bd)2+(cd)2==(a2+b2+c2)d2

( a d ) 3 + ( b d ) 3 + ( c d ) 3 = = ( a 3 + b 3 + c 3 ) ∗ d 3 (ad)^3 + (bd)^3 + (cd)^3 == ({a^3} + {b^3} + {c^3}) * {d^3} (ad)3+(bd)3+(cd)3==(a3+b3+c3)d3

add操作:a、b、c为原数,d为add标记,len为区间长度(此处为3)

一次幂更新操作: ( a + d ) + ( b + d ) + ( c + d ) = = ( a + b + c ) + d ∗ l e n (a+d) + (b+d) + (c+d) == ({a} + {b} + {c}) + {d * len} (a+d)+(b+d)+(c+d)==(a+b+c)+dlen

二次幂更新操作:

( a + d ) 2 + ( b + d ) 2 + ( c + d ) 2 = = ( a 2 + b 2 + c 2 ) + ( 2 a + 2 b + 2 c ) ∗ d + d 2 ∗ l e n (a+d)^2 + (b+d)^2 + (c+d)^2 == ({a^2} + {b^2} + {c^2}) + (2a+2b+2c) * d + {d^2 * len} (a+d)2+(b+d)2+(c+d)2==(a2+b2+c2)+(2a+2b+2c)d+d2len

( a + d ) 2 + ( b + d ) 2 + ( c + d ) 2 = = ( a 2 + b 2 + c 2 ) + 2 ∗ ( a + b + c ) ∗ d + d 2 ∗ l e n (a+d)^2 + (b+d)^2 + (c+d)^2 == ({a^2} + {b^2} + {c^2}) + 2*(a+b+c) * d + {d^2 * len} (a+d)2+(b+d)2+(c+d)2==(a2+b2+c2)+2(a+b+c)d+d2len

三次幂更新操作:

( a + d ) 3 + ( b + d ) 3 + ( c + d ) 3 = = ( a 3 + b 3 + c 3 ) + ( 3 a 2 + 3 b 2 + 3 c 2 ) ∗ d + ( 3 a + a b + 3 c ) ∗ d + d 3 ∗ l e n (a+d)^3 + (b+d)^3 + (c+d)^3 == ({a^3} + {b^3} + {c^3}) + (3a^2+3b^2+3c^2) * d + (3a+ab+3c) * d + {d^3 * len} (a+d)3+(b+d)3+(c+d)3==(a3+b3+c3)+(3a2+3b2+3c2)d+(3a+ab+3c)d+d3len

( a + d ) 3 + ( b + d ) 3 + ( c + d ) 3 = = ( a 3 + b 3 + c 3 ) + ( a 2 + b 2 + c 2 ) ∗ 3 ∗ d + ( a + b + c ) ∗ 3 ∗ d + d 3 ∗ l e n (a+d)^3 + (b+d)^3 + (c+d)^3 == ({a^3} + {b^3} + {c^3}) + (a^2+b^2+c^2) * 3* d + (a+b+c) *3* d + {d^3 * len} (a+d)3+(b+d)3+(c+d)3==(a3+b3+c3)+(a2+b2+c2)3d+(a+b+c)3d+d3len

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int mod = 10007;
typedef long long ll;
int tree[N << 2][4],add[N << 2],mult[N << 2],same[N << 2];
void push_same(int id,int x,int len)
{
    same[id] = x;
    add[id] = 0;
    mult[id] = 1;

    tree[id][1] = (len * x) % mod;
    tree[id][2] = (tree[id][1] * x) % mod;
    tree[id][3] = (tree[id][2] * x) % mod;
}
void push_mult(int id,int x,int len)
{
    mult[id] = (mult[id] * x) % mod;    
    add[id] = (add[id] * x) % mod;

	/// mult[id] 之前已经计算过了,这次计算x,x^2,x^3即可
    int tem = x;
    tree[id][1] = (tree[id][1] * tem) % mod;
    tem = (tem * x) % mod;
    tree[id][2] = (tree[id][2] * tem) % mod;
    tem = (tem * x) % mod;
    tree[id][3] = (tree[id][3] * tem) % mod;
}
void push_add(int id,int x,int len)  
{
    add[id] = (add[id] + x) % mod;

    int sum1 = tree[id][1];
    int sum2 = tree[id][2];

    int tem = x % mod;
    tree[id][1] += (tem * len) % mod;;
    tree[id][1] %= mod;

    int tem2 = (tem * x) % mod;
    tree[id][2] += (2 * sum1 * tem) % mod + (tem2 * len) % mod;
    tree[id][2] %= mod;

    int tem3 = (tem2 * x) % mod;
    tree[id][3] += (3 * sum2 * tem) % mod + (3 * sum1 * tem2) % mod + (tem3 * len) % mod;
    tree[id][3] %= mod;
}
void push_down(int id,int len)
{
    if (same[id]){
        push_same(id << 1,same[id],len - (len >> 1));
        push_same(id << 1 | 1,same[id],len >> 1);
        same[id] = 0;
    }
    if (mult[id] != 1){
        push_mult(id << 1,mult[id],len - (len >> 1));
        push_mult(id << 1 | 1,mult[id],len >> 1);
        mult[id] = 1;
    }
    if (add[id]){
        push_add(id << 1,add[id],len - (len >> 1));
        push_add(id << 1 | 1,add[id],len >> 1);
        add[id] = 0;
    }
}
void push_up(int id)
{
    tree[id][1] = (tree[id << 1][1] + tree[id << 1 | 1][1]) % mod;
    tree[id][2] = (tree[id << 1][2] + tree[id << 1 | 1][2]) % mod;
    tree[id][3] = (tree[id << 1][3] + tree[id << 1 | 1][3]) % mod;
}
void update(int a,int b,int op,int x,int l,int r,int id)
{
    if (a <= l && r <= b){
        if (op == 1) push_add(id,x,r - l + 1);
        else if (op == 2) push_mult(id,x,r - l + 1);
        else push_same(id,x,r - l + 1);
        return ;
    }
    push_down(id,r - l + 1);
    int mid = (l + r) >> 1;
    if (a <= mid) update(a,b,op,x,l,mid,id << 1);
    if (b > mid) update(a,b,op,x,mid + 1,r,id << 1 | 1);
    push_up(id);
}
int query(int a,int b,int x,int l,int r,int id)
{
    if (a <= l && r <= b) return tree[id][x];
    push_down(id,r - l + 1);
    int ans = 0;
    int mid = (l + r) >> 1;
    if (a <= mid) ans += query(a,b,x,l,mid,id << 1);
    if (b > mid) ans += query(a,b,x,mid + 1,r,id << 1 | 1);
    push_up(id);
    return ans % mod;
}
void build(int l,int r,int id)
{
    same[id] = add[id] = 0;
    mult[id] = 1;
    tree[id][1] = tree[id][2] = tree[id][3] = 0;
    if (l != r){
        int mid = (l + r) >> 1;
        build(l,mid,id << 1);
        build(mid + 1,r,id << 1 | 1);
    }
}
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m) == 2){
        if (!n && !m) break;
        build(1,n,1);
        for (int i = 0; i < m; i++){
            int op,x,y,c;
            scanf("%d %d %d %d",&op,&x,&y,&c);
            if (op != 4) update(x,y,op,c,1,n,1);
            else printf("%d\n",query(x,y,c,1,n,1));
        }
    }
    return 0;
}


HUD 4553 题目链接

线段树求区间并,有两种标记
区间的左连续区间等于左儿子的左连续区间,当左儿子左连续区间满了就加上右儿子的左区间
区间的右连续区间等于右儿子的右连续区间,当右儿子右连续区间满了就加上左儿子的右区间
区间最大连续区间等于 (左儿子的最大,右儿子的最大,左儿子的右区间加上右儿子的左区间)三个中的最大

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int mod = 10007;
typedef long long ll;
struct node{
    int ls,rs,ms;    /// 左边连续区间,右边连续区间,最大连续区间
}tree[N << 2][2];   /// 0屌丝,1女神
int lazy[N << 2][2];
void build(int l,int r,int id)
{
    lazy[id][0] = lazy[id][1] = -1;
    tree[id][0].ls = tree[id][0].rs = tree[id][0].ms = r - l + 1;
    tree[id][1].ls = tree[id][1].rs = tree[id][1].ms = r - l + 1;
    if (l != r){
        int mid = (l + r) >> 1;
        build(l,mid,id << 1);
        build(mid + 1,r,id << 1 | 1);
    }
}
void push_down(int id,int len,int k)
{
    tree[id << 1][k].ls = tree[id << 1][k].rs = tree[id << 1][k].ms = (len - (len >> 1)) * lazy[id][k];
    tree[id << 1 | 1][k].ls = tree[id << 1 | 1][k].rs = tree[id << 1 | 1][k].ms = (len >> 1) * lazy[id][k];
    lazy[id << 1][k] = lazy[id << 1 | 1][k] = lazy[id][k];
    lazy[id][k] = -1;
}
void push_up(int id,int len,int k)
{
    tree[id][k].ls = tree[id << 1][k].ls;
    tree[id][k].rs = tree[id << 1 | 1][k].rs;
    if (len - (len >> 1) == tree[id << 1][k].ls) tree[id][k].ls += tree[id << 1 | 1][k].ls;
    if (len >> 1 == tree[id << 1 | 1][k].rs) tree[id][k].rs += tree[id << 1][k].rs;
    tree[id][k].ms = max(tree[id << 1][k].rs + tree[id << 1 | 1][k].ls,max(tree[id << 1][k].ms,tree[id << 1 | 1][k].ms));
}
void update(int a,int b,int x,int k,int l,int r,int id)
{
    if (a <= l && r <= b){
        lazy[id][k] = x;
        tree[id][k].ls = tree[id][k].rs = tree[id][k].ms = (r - l + 1) * x;
        return ;
    }
    if (lazy[id][k] != -1) push_down(id,r - l + 1,k);
    int mid = (l + r) >> 1;
    if (a <= mid) update(a,b,x,k,l,mid,id << 1);
    if (b > mid) update(a,b,x,k,mid + 1,r,id << 1 | 1);
    push_up(id,r - l + 1,k);
}
int query(int x,int k,int l,int r,int id)
{
    if (l == r) return l;
    if (lazy[id][k] != -1) push_down(id,r - l + 1,k);
    int mid = (l + r) >> 1;
  //  cout << "id = " << id << " " << tree[id << 1][0].ms << " " << tree[id << 1][0].rs + tree[id << 1 | 1][0].ls << endl;
    if (tree[id << 1][k].ms >= x) return query(x,k,l,mid,id << 1);
    else if (tree[id << 1][k].rs + tree[id << 1 | 1][k].ls >= x) return mid - tree[id << 1][k].rs + 1;
    else return query(x,k,mid + 1,r,id << 1 | 1);
}
int main()
{
    int t,Case = 1;
    scanf("%d",&t);
    while(t--){
        int n,m;
        printf("Case %d:\n",Case++);
        scanf("%d %d",&n,&m);
        build(1,n,1);
        char str[22];
        int a,b;
        for (int i = 0; i < m; i++){
            scanf("%s",str);
            if (str[0] == 'D'){
                scanf("%d",&a);
              //  cout << "tree10 = " << tree[1][0].ms << endl;
              //  cout << "tree11 = " << tree[1][1].ms << endl;
                if (tree[1][0].ms >= a){
                    int x = query(a,0,1,n,1);
                    printf("%d,let's fly\n",x);
                    update(x,x + a - 1,0,0,1,n,1);
                }
                else printf("fly with yourself\n");
            }
            else if (str[0] == 'N'){
                scanf("%d",&a);
              //  cout << "tree10 = " << tree[1][0].ms << endl;
               // cout << "tree11 = " << tree[1][1].ms << endl;
                if (tree[1][0].ms >= a){
                    int x = query(a,0,1,n,1);
                    update(x,x + a - 1,0,0,1,n,1);
                    update(x,x + a - 1,0,1,1,n,1);
                    printf("%d,don't put my gezi\n",x);
                }
                else if (tree[1][1].ms >= a){
                    int x = query(a,1,1,n,1);
                    update(x,x + a - 1,0,0,1,n,1);
                    update(x,x + a - 1,0,1,1,n,1);
                    printf("%d,don't put my gezi\n",x);
                }
                else {
                    printf("wait for me\n");
                }
            }
            else {
                scanf("%d %d",&a,&b);
                printf("I am the hope of chinese chengxuyuan!!\n");
                update(a,b,1,0,1,n,1);
                update(a,b,1,1,1,n,1);
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值