• BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )


    从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献, 答案就是N-x. 用LCT维护加边, 可持久化线段树维护询问. O(NlogN)

    ------------------------------------------------------------------------------------

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    const int maxn = 200009;
     
    int N, M, Q, typ;
    int ntr[maxn], par[maxn], sm[maxn], buf[16];
     
    inline int getint() {
    char c = getchar();
    for(; !isdigit(c); c = getchar());
    int ret = 0;
    for(; isdigit(c); c = getchar())
    ret = ret * 10 + c - '0';
    return ret;
    }
     
    inline void putint(int x) {
    if(!x) {
    puts("0"); return;
    }
    int n = 0;
    for(; x; x /= 10)
    buf[n++] = x % 10;
    while(n--)
    putchar(buf[n] + '0');
    puts("");
    }
     
    int Find(int x) {
    return x == par[x] ? x : par[x] = Find(par[x]);
    }
     
    struct edge {
    int u, v;
    } e[maxn];
     
    struct Node* Null;
     
    struct Node {
    Node *ch[2], *p, *fa, *mn;
    bool iR, rev;
    int n;
    inline void setc(Node* c, int t) {
    (ch[t] = c)->p = this;
    }
    inline void pd() {
    if(rev) {
    swap(ch[0], ch[1]);
    ch[0]->rev ^= 1;
    ch[1]->rev ^= 1;
    rev = false;
    }
    }
    inline void upd() {
    mn = this;
    if(ch[0] != Null && mn->n > ch[0]->mn->n) mn = ch[0]->mn;
    if(ch[1] != Null && mn->n > ch[1]->mn->n) mn = ch[1]->mn;
    }
    inline int d() {
    return this == p->ch[1];
    }
    inline void setR() {
    fa = p, p = Null;
    iR = true;
    }
    } pool[maxn << 1], *T, *V[maxn], *stk[maxn << 1];
     
    void Init_LCT() {
    T = pool;
    T->ch[0] = T->ch[1] = T;
    T->fa = T->p = T->mn = T;
    T->n = maxn;
    Null = T++;
    }
     
    Node* Newnode(int n) {
    T->n = n;
    T->ch[0] = T->ch[1] = Null;
    T->fa = T->p = Null;
    T->iR = true, T->rev = false;
    return T++;
    }
     
    void Rot(Node* t) {
    Node* p = t->p;
    p->pd(), t->pd();
    int d = t->d();
    p->p->setc(t, p->d());
    p->setc(t->ch[d ^ 1], d);
    t->setc(p, d ^ 1);
    p->upd();
    if(p->iR) {
    p->iR = false;
    t->iR = true;
    t->fa = p->fa;
    }
    }
     
    void Splay(Node* t) {
    int n = 0;
    for(Node* o = t; o != Null; o = o->p) stk[n++] = o;
    while(n--) stk[n]->pd();
    for(Node* p = t->p; p != Null; p = t->p) {
    if(p->p != Null)
    p->d() != t->d() ? Rot(t) : Rot(p);
    Rot(t);
    }
    t->upd();
    }
     
    void Access(Node* t) {
    for(Node* o = Null; t != Null; o = t, t = t->fa) {
    Splay(t);
    t->ch[1]->setR();
    t->setc(o, 1);
    }
    }
     
    void makeRoot(Node* t) {
    Access(t);
    Splay(t);
    t->rev ^= 1;
    }
     
    Node* Path(Node* u, Node* v) {
    makeRoot(u);
    Access(v), Splay(v);
    return v;
    }
     
    void Join(Node* u, Node* v) {
    makeRoot(u);
    u->fa = v;
    }
     
    void Cut(Node* u, Node* v) {
    makeRoot(u);
    Access(v), Splay(v);
    u->p = Null, u->setR();
    v->setc(Null, 0), v->upd();
    }
     
    namespace F {
    int Val;
    struct Node {
    Node *lc, *rc;
    int n;
    } pool[maxn * 80], *pt, *Null, *Root[maxn];
    void Init() {
    pt = pool;
    pt->lc = pt->rc = pt;
    pt->n = 0;
    Root[0] = Null = pt++;
    }
    Node* Modify(Node* t, int l, int r) {
    Node* o = pt++;
    o->n = t->n + 1;
    if(l != r) {
    int m = (l + r) >> 1;
    if(Val <= m) {
    o->lc = Modify(t->lc, l, m);
    o->rc = t->rc;
    } else {
    o->lc = t->lc;
    o->rc = Modify(t->rc, m + 1, r);
    }
    }
    return o;
    }
    }
     
    int main() {
    N = getint(), M = getint();
    Q = getint(), typ = getint();
    Init_LCT();
    for(int i = 0; i < N; i++)
    par[i] = i, V[i] = Newnode(maxn);
    for(int i = 1; i <= M; i++) {
    int &u = e[i].u, &v = e[i].v;
    u = getint() - 1, v = getint() - 1;
    if(u == v) {
    ntr[i] = maxn;
    continue;
    }
    int _u = Find(u), _v = Find(v);
    Node* t = Newnode(i);
    if(_u == _v) {
    Node* mn = Path(V[u], V[v])->mn;
    Cut(V[e[mn->n].u], mn);
    Cut(V[e[mn->n].v], mn);
    ntr[i] = mn->n;
    } else {
    ntr[i] = 0;
    par[_u] = _v;
    }
    Join(t, V[u]), Join(t, V[v]);
    }
    F::Init();
    for(int i = 1; i <= M; i++) if(ntr[i] >= 1 && ntr[i] <= M) {
    F::Val = ntr[i];
    F::Root[i] = F::Modify(F::Root[i - 1], 1, M);
    } else 
    F::Root[i] = F::Root[i - 1];
    sm[0] = 0;
    for(int i = 1; i <= M; i++)
    sm[i] = sm[i - 1] + !ntr[i];
    int ans = 0, l, r;
    while(Q--) {
    l = getint(), r = getint();
    if(typ)
    l ^= ans, r ^= ans;
    int p = l - 1;
    ans = sm[r] - sm[p];
    F::Node *L = F::Root[p], *R = F::Root[r];
    l = 1, r = M;
    while(l < r) {
    int m = (l + r) >> 1;
    if(m <= p) {
    ans += R->lc->n - L->lc->n;
    L = L->rc, R = R->rc;
    l = m + 1;
    } else {
    L = L->lc, R = R->lc;
    r = m;
    }
    }
    putint(ans = N - ans);
    }
    return 0;
    }

    ------------------------------------------------------------------------------------

    3514: Codechef MARCH14 GERALD07加强版

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 685  Solved: 232
    [Submit][Status][Discuss]

    Description

    N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

    Input

    第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
    接下来M行,代表图中的每条边。
    接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

    Output

     K行每行一个整数代表该组询问的联通块个数。

    Sample Input

    3 5 4 0
    1 3
    1 2
    2 1
    3 2
    2 2
    2 3
    1 5
    5 5
    1 2

    Sample Output

    2
    1
    3
    1

    HINT

    对于100%的数据,1≤N、M、K≤200,000。

    Source

  • 相关阅读:
    aaa
    记一次Vue实战总结
    Data too long for column 'xxx' at row 1MySql.Data.MySqlClient.MySqlPacket ReadPacket() 报错解决
    uni-app 监听返回按钮
    微信H5分享外部链接,缩略图不显示
    uni-app 动态控制下拉刷新
    vueX 的使用
    uni-app H5 腾讯地图无法导航
    uni-app支付功能
    hooks 与 animejs
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5177193.html
Copyright © 2020-2023  润新知