kuangbin带你飞----线段树专题一(基础操作,单点,区间更新和查询)


A

题意:给出q个询问,单点更新和查询

主要是注意模板的书写

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<string>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
const int N = 5e5 + 10;
int num[4 * N];
int lazy[4 * N];
int T;
int n;
void pushup(int root)
{
    num[root] = num[root << 1] + num[root << 1 | 1];
}
void build(int l, int r, int root)
{
    if (l == r) {
        num[root] = 0; return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, root << 1);
    build(mid + 1, r, root << 1 | 1);
    pushup(root);
}
void update(int l, int r, int root, int pos, int val)
{
    if (l == r)
    {
        num[root] += val;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid)update(l, mid, root << 1, pos, val);
    else update(mid + 1, r, root << 1 | 1, pos, val);
    pushup(root);
}
int querry(int l, int r, int root ,int lf, int rt)
{
    if (lf <= l && r <= rt)return num[root];
    int mid = (l + r) >> 1;
    int ans = 0;
    if (lf <= mid)ans+=querry(l, mid, root << 1, lf, rt);
    if (rt > mid)ans+=querry(mid + 1, r, root << 1 | 1, lf, rt);
    return ans;
}
int main()
{
    T = read();
    for (int i = 1; i <= T; i++)
    {
        string s;
        n = read();
        build(1, n, 1);
        int x;
        up(i, 0, n)
        {
            x = read(); update(1, n, 1, i + 1, x);
        }
        printf("Case %d:\n", i);
        while (cin >> s && s != "End")
        {
            if (s == "Query")
            {
                int x, y; x = read(), y = read();
                cout << querry(1, n, 1, x, y) << endl;
            }
            if (s == "Add")
            {
                int p, v;
                p = read(), v = read();
                update(1, n, 1, p, v);
            }
            if (s == "Sub")
            {
                int p, v;
                p = read(), v = read();
                update(1, n, 1, p, -v);
            }
        }
    }
    return 0;
}

B

## 题意:单点更新,区间查询最大值,这种情况需要利用pushup来进行更新,每一次更新回溯到根节点,每一次更改最多被修改logn个点保证时间复杂度。

C

题意:区间更新和查询。

注意 需要灵活运用lazy标记,我们为什么要用lazy标记是因为对于单点更新来说,我们沿着一条链向下更新最多有logn个节点被更新到了,总体nlogn的复杂度,而如果时区间更新我们仍然用以上的更新的方式,那么时间复杂度时nlogn*(每一次区间长度)那么肯定是很容易T掉的,我们加入lazy标记后,每一次查询和添加都只需要log次,标记会随着我们对于这一棵树的遍历而跟随我们遍历,大大减少了时间复杂度。
------

D

模板,求区间覆盖的不同的个数。我们可以看出实质是对区间进行染色,区间更新,并且整体查询我这里保存了每一种颜色然后查询到叶子节点,看这个颜色是否被访问过了,没有的话答案+1。同样灵活运用lazy标记即可,先进行离散化,然后区间更新。

值得注意的是,我们离散话例如,(1,10),(1,3),(5,10)的区间的时候,如果进行区间染色那么1-3被染成1颜色,5-10被染成2颜色,4的话还有1- 10的颜色,答案为3,如果简单离散化的话,就会出现1-10查询结果为2,以为你1 3 5 10离散成为了1 2 3 4,区间更新了1 2,3 4,可以发现问题出现在了3和5身上,应该在3 5之间加一个数字,3 4 5 的话就不会出现任何问题了。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
const int N = 1e4 + 10;
vector<int>vec;
vector<pir>a;
int lazy[N << 4];
int num[N << 4];
int vis[N << 4];
int c,n,ans;
void pushdown(int root)
{
    if (lazy[root])
    {
        lazy[root << 1] = lazy[root];
        lazy[root << 1 | 1] = lazy[root];
        num[root << 1] = lazy[root];
        num[root << 1 | 1] = lazy[root];
        lazy[root] = 0;
    }
}
void build(int l, int r, int root)
{
    lazy[root] = 0;
    num[root] = 0;
    if (l == r) { return; }
    int mid = (l + r) >> 1;
    build(l, mid, root << 1);
    build(mid + 1, r, root << 1 | 1);
}
void update(int l, int r, int root, int val, int lf,int rt)
{
    if (lf <= l && r <= rt)
    {
        num[root] = val;
        lazy[root] = val;
        return;
    }
    pushdown(root);
    int mid = (l + r) >> 1;
    if (lf <= mid)update(l, mid, root << 1, val, lf, rt);
    if (rt > mid)update(mid + 1, r, root << 1 | 1, val, lf, rt);
}
void querry(int l, int r, int root,int pos)
{
    if (l == r)
    {
        if (num[root] == 0)return;
        //cout << "l" << l << "r" << r << endl;
        if (!vis[num[root]])
            ans++, vis[num[root]] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    pushdown(root);
    if (mid < pos)querry(mid + 1, r, root << 1 | 1, pos);
    else querry(l, mid, root << 1, pos);
}
int main()
{
    c = read();
    while (c--)
    {
        ans = 0;
        n = read();
        memset(vis, 0, sizeof(vis));
        a.clear();
        vec.clear();
        int x, y;
        up(i, 0, n)
        {
            x = read(), y = read();
            vec.push_back(x), vec.push_back(y);
            a.push_back(make_pair(x, y));
        }
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        int len = vec.size() - 1;
        up(i, 0, len)
        {
            if (vec[i] < vec[i + 1] - 1)
            {
                vec.push_back(vec[i] + 1);
            }
        }
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        build(1, vec.size(), 1);
        up(i, 0, n)
        {
            int pos1 = lower_bound(vec.begin(), vec.end(), a[i].first) - vec.begin();
            int pos2 = lower_bound(vec.begin(), vec.end(), a[i].second) - vec.begin();
            pos1++, pos2++;
            update(1, vec.size(), 1, i + 1, pos1, pos2);
        }
        upd(i, 1,vec.size())
        {
            querry(1, vec.size(), 1, i);
        }
        cout << ans << endl;
    }
    return 0;
}

E

区间更新整体查询,每一次更新,直接推到整个区间,然后下方标记。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
const int N = 1e5 + 10;
int t, n, q;
int tree[N << 2];
int lazy[N << 2];
void pushup(int root)
{
    tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
void pushdown(int l,int r,int root)
{
    if (lazy[root])
    {
        lazy[root << 1] = lazy[root];
        lazy[root << 1 | 1] = lazy[root];
        int mid = (l + r) >> 1;
        tree[root<<1] = lazy[root] * (mid - l + 1);
        tree[root << 1 | 1] = lazy[root] * (r - mid);
        lazy[root] = 0;
    }
}
void build(int l,int r,int root)
{
    lazy[root] = 0;
    if (l == r)
    {
        tree[root] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, root << 1);
    build(mid + 1, r, root << 1 | 1);
    pushup(root);
}
void update(int l, int r, int root, int lf, int rt,int val)
{
    if (lf <= l && r <= rt)
    {
        tree[root] = val * (r - l + 1);
        lazy[root] = val; return;
    }
    pushdown(l, r, root);
    int mid = (l + r) >> 1;
    if (lf <= mid)update(l, mid, root << 1, lf, rt, val);
    if(rt>mid) update(mid + 1, r, root << 1 | 1, lf, rt, val);
    pushup(root);
}
int querry(int l, int r, int root, int lf, int rt)
{
    if (lf <= l && r <= rt)
    {
        return tree[root];
    }
    pushdown(l,r,root);
    int mid = (l + r) >> 1;
    int ans = 0;
    if (lf <= mid)ans += querry(l, mid, root << 1, lf, rt);
    if (rt > mid)ans += querry(mid+1, r, root << 1 | 1, lf, rt);
    return ans;
}
int main()
{
    t = read();
    upd(i, 1, t)
    {
        n = read(), q = read();
        build(1, n, 1);
        while (q--)
        {
            int x, y, z;
            x = read(), y = read(), z = read();
            update(1, n, 1, x, y, z);
        }
        printf("Case %d: The total value of the hook is %d.\n", i, querry(1, n, 1, 1, n));
    }
    return 0;
}

F

## 和之间差不多

G

很有意思的一道题目,每一次区间更新,所有val开根号,区间查询最大值。由于val最大再int范围内,所以开根号最多32次就会变成1,所以我们就下到每一层去更新所有的点,然后区间值为长度(即整个区间每一个值都是1)就跳过不再更新。总体来说上限是32*nlogn的复杂度。

坑点在于输入的x,y大小关系不确定。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
const int N = 1e5 + 10;
ll tree[N << 2];
ll len[N << 2];
void pushup(int root)
{
    tree[root] = tree[root << 1] + tree[root << 1 | 1];
//  len[root] = len[root << 1] + len[root << 1 | 1];
}
void build(int l,int r,int root)
{
    tree[root] = 0;
    if (l == r) { scanf("%lld",&tree[root]); return; }
    int mid = (l + r) >> 1;
    build(l, mid, root << 1);
    build(mid + 1, r, root << 1 | 1);
    pushup(root);
}
void update(int l, int r, int root, int lf, int rt)
{
    if (l == r) { tree[root] = (ll)sqrt(tree[root]); return; }
    if (lf <= l && r <= rt&&tree[root]==r-l+1)
    {
        return;
    }
    int mid = (l + r) >> 1;
    if (lf <= mid)update(l, mid, root << 1, lf, rt);
    if (mid < rt)update(mid + 1, r, root << 1 | 1, lf, rt);
    pushup(root);
}
ll querry(int l, int r, int root, int lf, int rt)
{
    if (lf <= l && r <= rt)
    {
        return tree[root];
    }
    int mid = (l + r) >> 1;
    ll ans = 0;
    if (lf <= mid)ans += querry(l, mid, root << 1, lf, rt);
    if (rt > mid)ans += querry(mid + 1, r, root << 1 | 1, lf, rt);
    return ans;
}
int n,m;
int p = 0;
int main()
{
    while (scanf("%d",&n)!=EOF)
    {
        p++;
        ll x,y;
        int t;
        build(1, n, 1);
        m = read();
        printf("Case #%d:\n", p);
        up(i, 0, m)
        {
            t = read();
            scanf("%lld %lld", &x, &y);
            if (x > y)swap(x, y);
            if (t == 1)printf("%lld\n", querry(1, n, 1, x, y));
            if (t == 0)update(1, n, 1, x, y);
        }
        cout << endl;
    }
    return 0;
}

I

题意:每次单点更新摧毁一个点,同样可以复位一个点,区间查询,以这个点为中心向两边发散能走多远。

可以有两种思路,一种是关于这个点左右二分长度,因为具有单调性

第二种就是直接查询,题目相当于求连续区间长度,我们如果用分治思想来考虑的话,包含当前节点的线序区间长度,要么全在左边要么全在右边,要么跨接中间。针对此我们每一次维护都维护当前区间左连续最长区间和右最长连续区间即可中间区间查询通过访问左子树的右连续区间和右子树左连续区间得到,那么三种情况都能访问到了。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
    char ch = getchar(); int x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
const int N = 5e4 + 10;
struct {
    int l, r;
}tree[N<<2];
int n, m;
stack<int >st;
void pushup(int root, int mid)
{
    tree[root].l = tree[root << 1].l;
    tree[root].r = tree[root << 1 | 1].r;
    if (tree[root].l == mid && tree[root << 1 | 1].l)tree[root].l = tree[root << 1 | 1].l;
    if (tree[root].r == mid + 1 && tree[root << 1].r)tree[root].r = tree[root << 1].r;
}
void build(int l, int r, int root)
{
    int mid = (l + r) >> 1;
    if (l == r) {
        tree[root].l = tree[root].r = l;
        return;
    }
    build(l, mid, root << 1);
    build(mid + 1, r, root << 1 | 1);
    pushup(root,mid);
}
void update(int l, int r, int root, int pos,int val)
{
    if (l == r)
    {
        if(val==0)
            tree[root].l = tree[root].r = 0;
        else tree[root].l = tree[root].r = l;
        return;
    }
    int mid = (l + r) >> 1;
    if (mid < pos)update(mid + 1, r, root << 1 | 1, pos, val);
    else update(l, mid, root << 1, pos, val);
    pushup(root,mid);
}
int querry(int l, int r, int root, int pos)
{
    if (l == r) {
        if (tree[root].l)return 1;
        else return 0;
    }
    if (tree[root].l&&tree[root].l >= pos)return tree[root].l - l + 1;
    if (tree[root].r&&tree[root].r <= pos)return r - tree[root].r + 1;
    int sum = 0;
    int mid = (l + r) >> 1;
    if (tree[root << 1].r&&tree[root << 1 | 1].l)
    {
        if (tree[root << 1].r <= pos && pos <= tree[root << 1 | 1].l)
            return tree[root << 1 | 1].l - tree[root << 1].r + 1;
    }
    if (pos <= mid)querry(l, mid, root << 1, pos);
    else querry(mid + 1, r, root << 1 | 1, pos);
}
char s[2];
int main()
{
    while (cin >> n>>m)
    {
        build(1, n, 1);
        while (!st.empty())st.pop();
        up(i, 0, m)
        {
            cin >> s;
            if (s[0] == 'D')
            {
                int x; x = read();
                update(1, n, 1, x, 0);
                st.push(x);
            }
            if (s[0] == 'R')
            {
                if (st.empty())continue;
                int top = st.top();
                st.pop();
                update(1, n, 1, top, 1);
            }
            if (s[0] == 'Q')
            {
                int x; x = read();
                printf("%d\n", querry(1, n, 1, x));
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LORDXX/p/11544527.html

时间: 2024-11-07 23:27:43

kuangbin带你飞----线段树专题一(基础操作,单点,区间更新和查询)的相关文章

Kuangbin 带你飞-线段树专题 题解

HDU 1166 敌兵布阵 单调更新区间查询和 #include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #inc

[kuangbin带你飞]之&#39;最小生成树 &#39;专题(未完成)

带飞网址: https://vjudge.net/article/187 专题六: POJ 1251 Jungle RoadsPOJ 1287 NetworkingPOJ 2031 Building a Space StationPOJ 2421 Constructing RoadsZOJ 1586 QS NetworkPOJ 1789 Truck HistoryPOJ 2349 Arctic NetworkPOJ 1751 HighwaysPOJ 1258 Agri-NetPOJ 3026 B

线段树专题—POJ 3667 Hotel(区间合并模板)

题意:给一个n和m,表示n个房间,m次操作,操作类型有2种,一种把求连续未租出的房间数有d个的最小的最左边的房间号,另一个操作时把从x到x+d-1的房间号收回. 分析:这是一个区间合并的典型应用,基本只要套套模板就好了 下面是对区间合并的解释: up函数:当修改完此时的区间时,为了维护该区间上面区间值的正确性,向上回朔更新上面区间的值 down函数:把延迟标记下传,并修改下面区间的值,维护下面区间的正确性区间 (需要注意的是,up函数只有需要更新的时候才需要用到,而down只要是带延迟标记操作时

基本线段树模板(建树、点/区间修改、查询)

线段树主要用于区间记录信息(如区间和.最大最小值等),首先是建树: 这里以求和为例: 1 const int MAXM=50000; //定义 MAXM 为线段最大长度 2 3 int a[MAXM+5],segtree[(MAXM<<2)+5]; // a 数组为 main 函数中读入的内容,segtree 数组为需要查询的数的信息(如和.最值等),树的空间大小为线段最大长度的四倍 4 5 void build(int o,int l,int r){ //传入的参数为 o:当前需要建立的结点

[kuangbin]带你飞之&#39;线段树&#39;专题(未完成)

// 带飞网址 https://vjudge.net/article/187 专题七 线段树 HDU 1166 敌兵布阵HDU 1754 I Hate It√ POJ 3468 A Simple Problem with IntegersPOJ 2528 Mayor's postersHDU 1698 Just a HookZOJ 1610 Count the ColorsPOJ 3264 Balanced LineupHDU 4027 Can you answer these queries?

跟着chengyulala刷题之[kuangbin带你飞]之&#39;并查集&#39;专题/斜眼笑

[kuangbin带你飞] 专题1-23 https://vjudge.net/article/187 专题五 并查集 POJ 2236 Wireless Network  http://poj.org/problem?id=2236POJ 1611 The Suspects  http://poj.org/problem?id=1611HDU 1213 How Many Tables  http://acm.hdu.edu.cn/showproblem.php?pid=1213HDU 3038

kuangbin带你飞专题一 简单搜索 题解

目录 [kuangbin带你飞]专题一 简单搜索 [kuangbin带你飞]专题一 简单搜索 总结:用时2天半终于把这个专题刷完了 对于最基础的dfs bfs 路径打印 状态转移也有了一点自己些微的理解 其实2天半可以压缩到1天半的 主要是自己太懒了...慢慢加油刷bin神的专题呀 从大二下学期开始学算法 一开始就知道这个专题 一开始对于这个专题里的所有问题感觉都好难啊..就直接放弃了 看lrj的书 现在看到这个专题还挺唏嘘的吧 突然觉得思维和想法也不是很难 果然是那个时候心不静&还是储量不够吗

「kuangbin带你飞」专题十八 后缀数组

layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kuangbin - 字符串 - 后缀数组 传送门 倍增法 struct DA{ bool cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } int t1[maxn],t2[maxn],c[maxn]; int r

「kuangbin带你飞」专题十二 基础DP

layout: post title: 「kuangbin带你飞」专题十二 基础DP author: "luowentaoaa" catalog: true tags: mathjax: true - kuangbin - 动态规划 传送门 A.HDU1024 Max Sum Plus Plus 题意 给你N个数,然后你分成M个不重叠部分,并且这M个不重叠部分的和最大. 思路 动态规划最大m字段和,dp数组,dp[i][j]表示以a[j]结尾的,i个字段的最大和 两种情况:1.第a[j