返回顶部

模板 - CDQ分治

https://nanti.jisuanke.com/t/41356

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

namespace FastIO {
#define BUF_SIZE 1000000
    bool IOError = 0;
    inline char NextChar() {
        static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
        if(pl == pr) {
            pl = buf, pr = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pr == pl) {
                IOError = 1;
                return -1;
            }
        }
        return *pl++;
    }
#undef BUF_SIZE

    inline bool Blank(char c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t';
    }

    template<class T> inline void Read(T &x) {
        char c;
        while(Blank(c = NextChar()));
        if(!IOError) {
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
    }

    template<class T> inline void PutChar(T x) {
        if(x > 9)
            PutChar(x / 10);
        putchar(x % 10 + '0');
    }

    template<class T> inline void Write(T &x) {
        PutChar(x);
        putchar('\n');
    }

}

using namespace FastIO;

const int MAXN = 2e5;

//因为题目的数据有0,所以全部+1偏移了一位
const int H = 2e5 + 1;
int bit[H + 5];

inline void clear() {
    memset(bit, 0, sizeof(bit));
}

inline void add(int x, int v) {
    for(; x <= H; x += x & -x) {
        bit[x] += v;
    }
}

inline void set0(int x) {
    for(; x <= H; x += x & -x) {
        bit[x] = 0;
    }
}

inline int sum(int x) {
    int res = 0;
    for(; x ; x -= x & -x) {
        res += bit[x];
    }
    return res;
}

struct Query {
    int top, x, d1;
    bool operator<(const Query &q)const {
        return x < q.x;
    }
} q[5 * MAXN + 5], tq[5 * MAXN + 5];

int ans[MAXN + 5];
bool vis[MAXN + 5];

//超过该界时不进行取消树状数组,直接重建,因为树状数组有很多加法、判断之类的,而memset快得多
const int BUILDLIMIT = 2e4;

void solve(const int &l, const int &r, bool fl = false) {
    if(l == r)
        return;
    if(!fl) {
        //only update,这个剪枝应该功能强大
        bool ou = true;
        for(int i = l; i <= r ; i++) {
            //发现询问操作,break
            if((q[i].top & 3) >= 2) {
                ou = false;
                break;
            }
        }
        if(ou) {
            sort(q + l, q + r + 1);
            return;
        }
    }
    int mid = (l + r) >> 1;
    solve(l, mid);
    solve(mid + 1, r);

    int i = l, j = mid + 1, top = 0;
    while(i <= mid || j <= r) {
        if(i > mid || (j <= r && q[j].x < q[i].x)) {
            //把右边的询问加进来
            if((q[j].top & 3) >= 2)
                tq[++top] = q[j];
            ++j;
        } else {
            //把左边的修改加进来
            if((q[i].top & 3) <= 1)
                tq[++top] = q[i];
            ++i;
        }
    }

    //真正进行的修改操作的次数,用来辅助判断直接重建,可能是负优化
    //int cnt=0;
    for(int i = 1, nxt; i <= top; i = nxt) {
        for(nxt = i + 1; nxt <= top && tq[i].x == tq[nxt].x; ++nxt);
        for(int j = i; j < nxt; ++j) {
            //把修改操作执行
            if((tq[j].top & 3) == 1) {
                add(tq[j].d1, 1);
                //++cnt;
            } else if((tq[j].top & 3) == 0) {
                add(tq[j].d1, -1);
                //++cnt;
            }
        }
        for(int j = i; j < nxt; ++j) {
            //把询问操作执行
            if((tq[j].top & 3) == 2) {
                //前面的转换已经把l可能产生的贡献已经清除了
                ans[tq[j].top >> 2] -= sum(tq[j].d1);
            } else if((tq[j].top & 3) == 3) {
                ans[tq[j].top >> 2] += sum(tq[j].d1);
                //op2和op3都是成对出现的,只对其中一个赋值就可以了
                vis[tq[j].top >> 2] = true;
            }
        }
    }

    if(!fl) {
        if(cnt < BUILDLIMIT) {
            for(int j = 1; j <= top; ++j) {
                //对应撤销修改操作
                if((tq[j].top & 3) == 1)
                    add(tq[j].d1, -1);
                else if((tq[j].top & 3) == 0)
                    add(tq[j].d1, +1);
            }
        } else {
            //直接重建
            clear();
        }
        merge(q + l, q + mid + 1, q + mid + 1, q + r + 1, tq + 1);
        for(int j = l; j <= r; ++j)
            q[j] = tq[j - l + 1];
    }
    return;
}

int a[MAXN + 5], b[MAXN + 5];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku

    int n, m;
    Read(n), Read(m);
    int qtop = 0;

    for(int i = 1; i <= n; ++i) {
        Read(a[i]);
        b[i] = (a[i] == a[i - 1]) ? 0 : a[i];

        q[++qtop].top = 1;
        q[qtop].x = i;
        q[qtop].d1 = b[i] + 1;
    }

    for(int i = 1, op; i <= m; ++i) {
        Read(op);
        if(op == 1) {
            int x, y;
            Read(x), Read(y);
            q[++qtop].top = i << 2;
            q[qtop].x = x;
            q[qtop].d1 = b[x] + 1;

            q[++qtop].top = i << 2;
            q[qtop].x = x + 1;
            q[qtop].d1 = b[x + 1] + 1;

            a[x] = y;
            b[x] = (a[x] == a[x - 1]) ? 0 : a[x];
            b[x + 1] = (a[x + 1] == a[x]) ? 0 : a[x + 1];

            q[++qtop].top = i << 2 | 1;
            q[qtop].x = x;
            q[qtop].d1 = b[x] + 1;

            q[++qtop].top = i << 2 | 1;
            q[qtop].x = x + 1;
            q[qtop].d1 = b[x + 1] + 1;
        } else {
            int l, r, x, y;
            Read(l), Read(r), Read(x), Read(y);
            //op2是要被减去的,op3是要被加上的
            q[++qtop].top = i << 2 | 2;
            //这里询问的就是要l而不是l-1,为了把l可能产生的贡献去掉然后加回来
            q[qtop].x = l;
            q[qtop].d1 = y + 1;

            q[++qtop].top = i << 2 | 3;
            //这里询问的就是要l而不是l-1,为了把l可能产生的贡献去掉然后加回来
            q[qtop].x = l;
            q[qtop].d1 = x - 1 + 1;

            q[++qtop].top = i << 2 | 3;
            q[qtop].x = r;
            q[qtop].d1 = y + 1;

            q[++qtop].top = i << 2 | 2;
            q[qtop].x = r;
            q[qtop].d1 = x - 1 + 1;

            //把l的贡献加回来
            if(x <= a[l] && a[l] <= y)
                ++ans[i];
        }
    }

    solve(1, qtop, true);
    for(int i = 1; i <= m; ++i) {
        if(vis[i])
            Write(ans[i]);
    }
}

天使玩偶

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

namespace FastIO {
#define BUF_SIZE 1000000
    bool IOError = 0;
    inline char NextChar() {
        static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
        if(pl == pr) {
            pl = buf, pr = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pr == pl) {
                IOError = 1;
                return -1;
            }
        }
        return *pl++;
    }
#undef BUF_SIZE

    inline bool Blank(char c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t';
    }

    template<class T> inline void Read(T &x) {
        char c;
        while(Blank(c = NextChar()));
        if(!IOError) {
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
    }

    template<class T> inline void Read2(T &x) {
        char c;
        bool f = 0;
        while(Blank(c = NextChar()));
        if(!IOError) {
            if(c == '-') {
                f = 1;
                c = NextChar();
            }
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
        if(f)
            x = -x;
    }

    template<class T> inline void PutChar(T x) {
        if(x > 9)
            PutChar(x / 10);
        putchar(x % 10 + '0');
    }

    template<class T> inline void Write(T &x) {
        PutChar(x);
        putchar('\n');
    }

    template<class T> inline void Write2(T &x) {
        if(x < 0) {
            putchar('-');
            PutChar(-x);
        } else
            PutChar(x);
        putchar('\n');
    }
}

using namespace FastIO;

const int INF = 0x3f3f3f3f;
//将题目的[0,1e6]偏移到[1,1e6+1]
const int H = 1e6 + 1;

int bit[H + 5];

inline void build() {
    memset(bit, INF, sizeof(bit));
}

void update(int x, int v) {
    for(; x <= H; x += x & -x) {
        if(v < bit[x])
            bit[x] = v;
    }
}

void unupdate(int x) {
    for(; x <= H; x += x & -x)
        bit[x] = INF;
}

int query(int x) {
    int res = INF;
    for(; x >= 1; x -= x & -x) {
        if(bit[x] < res)
            res = bit[x];
    }
    return res;
}

const int MAXNM = 1e6;

struct Query {
    int op, x, y;
    bool operator<(const Query &q)const {
        return x < q.x;
    }
} q[MAXNM + 5], tq[MAXNM + 5];

inline int before_calc(int l, int r) {
    int mid = (l + r) >> 1;
    int i = l, j = mid + 1, top = 0;
    while(i <= mid || j <= r) {
        if(i > mid || (j <= r && q[j].x < q[i].x)) {
            //把右边的询问加进来
            if((q[j].op & 1) == 0)
                tq[++top] = q[j];
            ++j;
        } else {
            //把左边的修改加进来
            if((q[i].op & 1) == 1)
                tq[++top] = q[i];
            ++i;
        }
    }
    return top;
}

inline void after_calc(int l, int r, int tqtop) {
    int mid = (l + r) >> 1;
    merge(q + l, q + mid + 1, q + mid + 1, q + r + 1, tq + 1);
    for(int j = l; j <= r; ++j)
        q[j] = tq[j - l + 1];
}

int ans[MAXNM + 5];

//超过该界时不进行取消树状数组,直接重建,因为树状数组有很多加法、判断之类的,而memset快得多
const int BUILDLIMIT = 5e4;

int calc_upleft(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, H - tq[i].y + 1);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = 1, nxt; i <= tqtop; i = nxt) {
            for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op & 1 && H - tq[j].y + 1 <= maxy) {
                    update(H - tq[j].y + 1, (-tq[j].x + tq[j].y));
                    ++cnt;
                }
            }
            for(int j = i; j < nxt; ++j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (tq[j].x - tq[j].y) + query(H - tq[j].y + 1));

            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && H - tq[i].y + 1 <= maxy)
                    unupdate(H - tq[i].y + 1);
            }
        } else
            build();
    }
}

int calc_downleft(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, tq[i].y);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = 1, nxt; i <= tqtop; i = nxt) {
            for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op & 1 && tq[j].y <= maxy) {
                    update(tq[j].y, (-tq[j].x - tq[j].y));
                    ++cnt;
                }
            }
            for(int j = i; j < nxt; ++j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (tq[j].x + tq[j].y) + query(tq[j].y));
            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && tq[i].y <= maxy)
                    unupdate(tq[i].y);
            }
        } else
            build();
    }
}

int calc_upright(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, H - tq[i].y + 1);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = tqtop, nxt; i >= 1; i = nxt) {
            for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
            for(int j = i; j > nxt; --j) {
                if(tq[j].op & 1 && H - tq[j].y + 1 <= maxy) {
                    update(H - tq[j].y + 1, (tq[j].x + tq[j].y));
                    ++cnt;
                }
            }
            for(int j = i; j > nxt; --j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (-tq[j].x - tq[j].y) + query(H - tq[j].y + 1));
            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && H - tq[i].y + 1 <= maxy)
                    unupdate(H - tq[i].y + 1);
            }
        } else
            build();
    }
}

int calc_downright(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, tq[i].y);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = tqtop, nxt; i >= 1; i = nxt) {
            for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
            for(int j = i; j > nxt; --j) {
                if(tq[j].op & 1 && tq[j].y <= maxy) {
                    ++cnt;
                    update(tq[j].y, (tq[j].x - tq[j].y));
                }
            }
            for(int j = i; j > nxt; --j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (-tq[j].x + tq[j].y) + query(tq[j].y));
            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && tq[i].y <= maxy)
                    unupdate(tq[i].y);
            }
        } else
            build();
    }
}

void solve(int l, int r, bool firstlayer = false) {
    if(l == r)
        return;
    if(!firstlayer) {
        bool all1 = true;
        for(int i = l; i <= r ; i++) {
            if(!(tq[i].op & 1)) {
                all1 = false;
                break;
            }
        }
        if(all1) {
            sort(q + l, q + r + 1);
            return;
        }
    }
    int mid = (l + r) >> 1;
    solve(l, mid);
    solve(mid + 1, r);
    //这里是没必要每一层都排序的,事实上是每一层直接归并就可以了
    int tqtop = before_calc(l, r);
    calc_upleft(tqtop);
    calc_downleft(tqtop);
    calc_upright(tqtop);
    calc_downright(tqtop);
    if(!firstlayer)
        after_calc(l, r, tqtop);
    return;
}


int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m;
    Read(n), Read(m);
    //scanf("%d%d", &n, &m);
    int qtop = 0;
    for(int i = 1; i <= n; ++i) {
        int x, y;
        Read(x), Read(y);
        ++qtop;
        q[qtop].op = qtop << 1 | 1;
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
    }
    for(int i = 1; i <= m; ++i) {
        int op, x, y;
        Read(op), Read(x), Read(y);
        ++qtop;
        q[qtop].op = (qtop << 1) | (op & 1);
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
    }
    build();
    memset(ans, INF, sizeof(ans[0]) * (n + m + 1));
    solve(1, qtop, true);
    const int MAXANS = 5e6;
    for(int i = 1; i <= qtop; ++i) {
        if(ans[i] <= MAXANS) {
            Write(ans[i]);
        }
    }
}
posted @ 2019-09-11 19:40  Inko  阅读(...)  评论(...编辑  收藏