数据结构

三道线段树题解

2017-10-14  本文已影响46人  失树

原题链接

A Simple Problem With Integers

#include<iostream>
#define MAXN 100000
using namespace std;
long long int a[MAXN+1];
struct segTreeNode {
    long long int a, b;
    long long int val;
    long long int flag;
}segTree[4*MAXN+5];
void buildTree(int id, int l, int r) {
    segTree[id].a = l;
    segTree[id].b = r;
    segTree[id].flag = 0;
    if (l == r) {
        segTree[id].val = a[l];
    }
    else {
        int mid = (l + r) / 2;
        buildTree(2 * id, l, mid);
        buildTree(2 * id + 1, mid + 1, r);
        segTree[id].val = segTree[2 * id].val + segTree[2 * id + 1].val;
    }
}
void change(int id, int l, int r, int plus) {
    long long int a = segTree[id].a;
    long long int b = segTree[id].b;
    if (a >= l&&b <= r) {
        segTree[id].flag += plus;//注意是+=不是等于!可能有叠加的情况的!
        segTree[id].val += (b - a + 1)*plus;
    }
    else {
        if (segTree[id].flag != 0) {
            segTree[2 * id].flag+=segTree[id].flag;//仔细考虑flag的事情!
            segTree[2 * id + 1].flag += segTree[id].flag;
            segTree[2 * id].val += (segTree[2 * id].b - segTree[2 * id].a + 1)*segTree[id].flag;
            segTree[2 * id+1].val += (segTree[2 * id+1].b - segTree[2 * id+1].a + 1)*segTree[id].flag;
            segTree[id].flag = 0;
        }
        long long int mid = (a + b) / 2;
        if (l <= mid) change(2 * id, l, r, plus);
        if (r > mid) change(2 * id + 1, l, r, plus);
        segTree[id].val = segTree[2 * id].val + segTree[2 * id + 1].val;
    }
}
long long int query(int id, int l, int r) {
    long long int a = segTree[id].a;
    long long int b = segTree[id].b;
    if (a >= l&&b <= r) return segTree[id].val;
    else {
        if (segTree[id].flag != 0) {
            segTree[2 * id].flag+=segTree[id].flag;
            segTree[2 * id + 1].flag += segTree[id].flag;
            segTree[2 * id].val += (segTree[2 * id].b - segTree[2 * id].a + 1)*segTree[id].flag;
            segTree[2 * id + 1].val += (segTree[2 * id + 1].b - segTree[2 * id + 1].a + 1)*segTree[id].flag;
            segTree[id].flag = 0;//重要!恢复成0
        }
        long long int mid = (a + b) / 2;
        long long int ans = 0;
        if (l <= mid) ans += query(id * 2, l, r);
        if (r > mid) ans += query(id * 2 + 1, l, r);
        return ans;
    }
}
int main() {
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    buildTree(1, 1, n);
    for (int i = 0; i < q; i++) {
        char op;
        cin >> op;
        if (op == 'Q') {
            int x, y;
            cin >> x >> y;
            cout << query(1, x, y) << endl;
        }
        else {
            int x, y, plus;
            cin >> x >> y >> plus;
            change(1, x, y, plus);
        }
    }
}

K-th Number

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 100005
#define LOGN 20
using namespace std;
int n, m;
int a[MAXN] = { 0 };            //原数组
int sorted[MAXN] = { 0 };       //记录排序后的数组
int tree[LOGN][MAXN] = { 0 };   //记录每层的元素序列
int sum[LOGN][MAXN] = { 0 };    //记录每层的[1,j]被划分到左子树的数目
void build(int layer,int l, int r) {
    int mid = (l + r) / 2;
    int lp = l;                                 //left pointer
    int rp = mid + 1;                           //right pointer
    int equalToMid = (mid - l + 1);             //为了让等于sorted[mid]的数相对均匀地分给两个子树
    /*for (int i = l; i <= mid; i++) {          //用equalToMid记录左半边等于mid的个数
        if (a[i] ==sorted[mid])
            equalToMid--;
    }*/
    for (int i = l; i <= r; i++) {
        if (i == l) sum[layer][i] = 0;
        else {
            sum[layer][i] = sum[layer][i-1];    //用dp来维护每层的sum数组
        }
        if (tree[layer][i] == sorted[mid]) {//为了让等于sorted[mid]的数相对均匀地分给两个子树
            /*if (equalToMid) {
                equalToMid--;
                sum[layer][i]++;
                tree[layer + 1][lp] = a[i];
                lp++;
            }
            else {
                tree[layer + 1][rp] = a[i];
                rp++;
            }*/
            if (lp <= mid) {
                sum[layer][i]++;
                tree[layer + 1][lp] = tree[layer][i];
                lp++;
            }
            else {
                tree[layer + 1][rp] = tree[layer][i];
                rp++;
            }
        }
        else if (tree[layer][i] < sorted[mid]){//tree[layer][i]会被分入左子树
            sum[layer][i]++;
            tree[layer + 1][lp] = tree[layer][i];
            lp++;
        }
        else {//tree[layer][i]会被分入右子树
            tree[layer + 1][rp] = tree[layer][i];
            rp++;
        }
    }
    if (l != r) {
        build(layer + 1, l, mid);
        build(layer + 1, mid + 1, r);
    }
}
int query(int layer, int l, int r, int askl, int askr,int k) {
    if (l == r) return tree[layer][l];
    int mid = (l + r) / 2;
    int sum0;                                   //[l,askl)被划分到左子树的数目
    int sum1;                                   //[askl,askr]被划分到左子树的数目
    if (l == askl) {
        sum0 = 0;
        sum1 = sum[layer][askr];
    }
    else {
        sum0 = sum[layer][askl - 1];
        sum1 = sum[layer][askr] - sum[layer][askl - 1];
    }
    if (k <= sum1) {//在左子树中查找,注意查找区间变更情况!
        //原先[l,ask1)被划分到左子树的部分肯定不在查找范围内,原先askr以后的数字也肯定不在查找范围内
        return query(layer + 1, l, mid, l+sum0, l+sum0+sum1-1, k);
    }
    else {//在右子树中查找
        //原先[l,ask1)被划分到右子树的部分(askl-l-sum0)不在查找范围内,原先askr以后的数字也肯定不在查找范围内
        //mid+1+askr-l+1-sum0-sum1
        //return query(layer + 1, mid + 1, r, mid+1+askl-l-sum0, (mid+1+askl-l-sum0)+(askr-askl+1-sum1), k - sum1);
        return query(layer + 1, mid + 1, r, mid + 1 + askl - l - sum0, mid + 1 - l - sum0 - sum1 + askr, k - sum1);
    }
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        tree[0][i] = a[i];
        sorted[i] = a[i];
    }
    sort(sorted + 1, sorted + n + 1);
    build(0,1, n);
    int askl, askr, k;
    for (int i = 1; i <= m; i++) {
        scanf("%d%d%d", &askl, &askr, &k);
        int ans = query(0, 1, n, askl, askr, k);
        printf("%d\n", ans);
    }
}

Lost Cows

/*
    第n个人的序号就是a[i]+1,标记vis[a[i]+1]=1
    从后往前,第n-1个人的序号就是第a[n-1]个未被访问的值
    时间为O(n^2)
*/
#include<iostream>
using namespace std;
int a[10000] = { 0 };
bool vis[10000] = { 0 };
int ans[10000] = { 0 };
int main() {
    int n;
    cin >> n;
    a[1] = 0;
    for (int i = 2; i <= n; i++) {
        cin >> a[i];
    }
    vis[0] = 1;
    for (int i = n; i >= 1; i--) {
        int beg = 0;
        //while (vis[beg]!=0) beg++;//考虑a[1]的情况

        //找到第a[i]+1个未被访问的数,即ans[i]
        for (int t = 1; t <= a[i]+1; t++) {
            beg++;
            while (vis[beg]!=0) beg++;
        }
        ans[i] = beg;
        vis[beg] = 1;
    }
    for (int i = 1; i <= n; i++) {
        cout << ans[i] << endl;
    }
}
/*
第n个人的序号就是a[i]+1,标记vis[a[i]+1]=1
从后往前,第n-1个人的序号就是第a[n-1]个未被访问的值
时间为O(n^2)
*/
#include<iostream>
using namespace std;
int a[10000] = { 0 };
bool vis[10000] = { 0 };
int ans[10000] = { 0 };
/*
    线段树[a,b]段表示此段上未被访问的数目
*/
struct node {
    int a, b;
    int val;
}tree[40000];
void build(int id, int l, int r) {
    tree[id].a = l;
    tree[id].b = r;
    tree[id].val = r - l + 1;
    if (l == r) return;
    else {
        int mid = (l + r) / 2;
        build(2 * id, l, mid);
        build(2 * id + 1, mid + 1, r);
    }
}
int query(int id, int x) {//query与change操作合而为一
    tree[id].val -= 1;
    int l = tree[id].a;
    int r = tree[id].b;
    if (l == r) return l;
    else {
        //int mid = (l + r) / 2;
        int lv = tree[2 * id].val;
        if (x > lv) {//右子树
            return query(2 * id + 1, x - lv);
        }
        else return query(2 * id, x);
    }
}
int main() {
    int n;
    cin >> n;
    a[1] = 0;
    for (int i = 2; i <= n; i++) {
        cin >> a[i];
    }
    build(1, 1, n);
    for (int i = n; i >= 1; i--) {
        ans[i] = query(1,a[i] + 1);//查找第a[i]+1个不为0的index
    }
    for (int i = 1; i <= n; i++) {
        cout << ans[i] << endl;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读