zoukankan      html  css  js  c++  java
  • noip2017D2T3的几种写法...(BIT/线段树/平衡树)

    题意各大oj上都有啦..想必来搜题解的都看过题面了...Qw

    Solution1:

      首先观察n=1的情况,显然就是中间删掉一个数后面加上一个数,并查询那个删掉的数(以后把这样一个过程称为一个操作啦((:)..

        就是你用什么都可以写..

      然后发现,完整的数据范围就是n+1个n=1的子问题

        就是前n行每行前m-1个数的n个子问题和最后一列的子问题..(有点乱乱啊..语文差..

      然而开n+1棵什么什么树肯定MLE.....下面以线段树为例

        :注意到一次操作,最多更改2log(n)个点,于是就可以愉快动态开点啦(^:

    (稍稍借鉴了一下jxc的写法,,好短好妙妙啊

    #include<bits/stdc++.h>
    using namespace std;
    
    const int M = 300000;
    
    struct Node{
        Node *lc, *rc;
        int l, r, val;
        Node(int l = 1, int r = M << 1) {
            this->lc = this->rc = NULL;
            this->l = l;
            this->r = r;
            this->val = r - l + 1;
        }
    };
    
    struct SegTree{
        Node *rt;
        vector<long long> add;
        SegTree(void) {
            rt = new Node();
            add.clear();
        }
        int Del(Node *p, int x) {
            p->val--;
            if(p->l == p->r) return p->l;
            int mid = (p->l + p->r) >> 1;
            int lcv = p->lc ? p->lc->val : mid - p->l + 1;
            if(lcv >= x) {
                if(!p->lc) p->lc = new Node(p->l, mid);
                return Del(p->lc, x);
            } else {
                if(!p->rc) p->rc = new Node(mid + 1, p->r);
                return Del(p->rc, x - lcv);
            }
        }
    }line[M + 10], row;
    
    int n, m, q, x, y;
    long long now;
    
    int main(void) {
        scanf("%d%d%d", &n, &m, &q);
        while(q--) {
            scanf("%d%d", &x, &y);
            int id = row.Del(row.rt, x);
            if(id <= n) now = 1LL * id * m;
            else now = row.add[id - n - 1];
            if(y != m) {
                line[x].add.push_back(now);
                int id = line[x].Del(line[x].rt, y);
                if(id < m) now = 1LL * (x - 1) * m + id;
                else now = line[x].add[id - m];
            }
            row.add.push_back(now);
            printf("%lld
    ", now);
        }
        return 0;
    }

    Solution2:

      注意到BIT不能动态开点(至少我不会啊ov

        于是考虑离线,稍微思考一下,,,,于是发现每一行的查询是独立的,也就是说可以离线之后只开一个BIT

          然后把每一行处理完之后再扔回去就可以保证所有行的查询操作是log的

      这样就预处理完啦

      剩下的就跟之前的一样做就行了(包括那一列的(因为那一列的操作每次都有啊..

    #include<bits/stdc++.h>
    using namespace std;
    
    const int M = 300100;
    
    int val[M << 1];
    vector<pair<int, int> > query[M];
    
    inline void Add(int x, int y) {
        for(; x <= M << 1; x += -x & x) val[x] += y;
    }
    
    inline int Qry(int x) {
        int res = 0;
        for(int i = 19; i >= 0; i--)
            if((1 << i) + res <= (M << 1)) {
                if(val[res + (1 << i)] < x) {
                    res += 1 << i;
                    x -= val[res];
                }    
            }
        return res + 1;
    }
    
    void Get_num(int *a, int x) {
        for(int i = 0; i < query[x].size(); i++) {
            pair<int, int> o = query[x][i];
            a[o.second] = Qry(o.first);
            Add(a[o.second], -1);
        }
        for(int i = 0; i < query[x].size(); i++) {
            pair<int, int> o = query[x][i];
            Add(a[o.second], 1);
        }
    }
    
    long long now;
    vector<long long> last[M];
    int n, m, q, x, y, qx[M], qy[M], row[M];
    
    int Read(void) {
        int x = 0; char ch = getchar();
        while(ch < '0' || ch > '9') ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        return x;
    }
    
    int main(void) {
        scanf("%d%d%d", &n, &m, &q);
        for(int i = 1; i <= q; i++) {
            x = Read(); y = Read();
            if(y != m) query[x].push_back(make_pair(y, i));
            qx[i] = x, qy[i] = y;
        }
        
        for(int i = 1; i <= M << 1; i++)
            Add(i, 1);
        for(int i = 1; i <= n; i++)
            Get_num(row, i);
            
        for(int i = 1; i <= q; i++) {
            int id = Qry(qx[i]);
            Add(id, -1);
            if(id <= n) now = 1LL * id * m;
            else now = last[0][id - n - 1];
            if(qy[i] < m) {
                last[qx[i]].push_back(now);
                int id = row[i];
                if(id < m) now = 1LL * (qx[i] - 1) * m + id;
                else now = last[qx[i]][id - m];
            }
            last[0].push_back(now);
            printf("%lld
    ", now);
        }
        return 0;
    }

    Solution3:

      据说可以trie做.....不会...

  • 相关阅读:
    【AHOI2009】 维护序列
    Codeforces Hello 2019 F. Alex and a TV Show[bitset+莫比乌斯反演]
    Codeforces Hello 2019 D. Makoto and a Blackboard[DP+数论+概率期望]
    Codeforces Hello 2019 ABCDF题解
    [BZOJ1042][HAOI2008]硬币购物[容斥原理+背包]
    Codeforces Round #529 (Div. 3)题解
    [BZOJ4311]向量[线段树分治+计算几何+二分/三分]
    [BZOJ1076][SCOI2008]奖励关[状压DP+概率期望]
    [POJ3368][UVA11235] Frequent values[ST表]
    [USACO5.5]矩形周长Picture[扫描线+线段树]
  • 原文地址:https://www.cnblogs.com/sffey/p/7895525.html
Copyright © 2011-2022 走看看