• BZOJ 3514: Codechef MARCH14 GERALD07加强版


    3514: Codechef MARCH14 GERALD07加强版

    Time Limit: 60 Sec  Memory Limit: 256 MB
    Submit: 1356  Solved: 514
    [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。


    2016.2.26提高时限至60s

    Source

    [Submit][Status][Discuss]

    如果是离线的话,我们可以LCT+莫队什么的乱搞是吧,但是在线就……

    不过还是有一个很喵的做法——

    我们用LCT维护一棵生成树,当加入一条边$i$的时候($i$是其编号),其连接的两个点可能已经联通,加入$i$之后会形成一个环,我们弹掉这个环上编号最小的边(也就是加入最早的边),并记录其编号为$ntr_{i}$。特殊的,如果$i$没有弹掉任何边,我们记$ntr_{i}=0$。

    对于一个询问$[L,R]$(表示我们只保留$e|ein [L,R]$),答案就是$n-sum_{i=L}^{R}{(ntr_{i}lt L)}$。这个就是主席树了。

    #include <cstdio>
    
    inline int nextChar(void) {
      static const int siz = 1 << 20;
      static char buf[siz];
      static char *hd = buf + siz;
      static char *tl = buf + siz;
      if (hd == tl)
        fread(hd = buf, 1, siz, stdin);
      return int(*hd++);
    }
    
    inline int nextInt(void) {
      register int ret = 0;
      register int neg = false;
      register int bit = nextChar();
      for (; bit < 48; bit = nextChar())
        if (bit == '-')neg ^= true;
      for (; bit > 47; bit = nextChar())
        ret = ret * 10 + bit - '0';
      return neg ? -ret : ret;
    }
    
    template <class T>
    inline void Swap(T &a, T &b) {
      T c;
      c = a;
      a = b;
      b = c;
    }
    
    template <class T>
    inline T Max(const T &a, const T &b) {
      return a > b ? a : b;
    }
    
    template <class T>
    inline T Min(const T &a, const T &b) {
      return a < b ? a : b;
    }
    
    const int mxn = 400005;
    const int inf = 1000000007;
    
    int n, m, q, e, ntr[mxn];
    
    struct edge {
      int x, y;
    }E[mxn];
    
    namespace LCT {
      int top = 0;
      int stk[mxn];
      int val[mxn];
      int rev[mxn];
      int min[mxn];
      int fat[mxn];
      int son[mxn][2];
    
      inline bool isroot(int t) {
        int f = fat[t];
        if (!f)return true;
        if (son[f][0] == t)return false;
        if (son[f][1] == t)return false;
        return true;
      }
    
      inline void update(int t) {
        min[t] = val[t];
        if (son[t][0])min[t] = Min(min[t], min[son[t][0]]);
        if (son[t][1])min[t] = Min(min[t], min[son[t][1]]);
      }
    
      inline void push(int t) {
        rev[t] = 0;
        Swap(son[t][0], son[t][1]);
        if (son[t][0])rev[son[t][0]] ^= 1;
        if (son[t][1])rev[son[t][1]] ^= 1;
      }
    
      inline void pushdown(int t) {
        for (stk[++top] = t; t; )
          stk[++top] = t = fat[t];
        for (; top; --top)
          if (rev[stk[top]])
          	push(stk[top]);
      }
    
      inline void connect(int t, int f, int s) {
        if (t)fat[t] = f;
        if (f)son[f][s] = t;
      }
    
      inline void rotate(int t) {
        int f = fat[t];
        int g = fat[f];
        int s = son[f][1] == t;
        connect(son[t][!s], f, s);
        connect(f, t, !s);
        fat[t] = g;
        if (g && son[g][0] == f)son[g][0] = t;
        if (g && son[g][1] == f)son[g][1] = t;
        update(f);
        update(t);
      }
    
      inline void splay(int t) {
        pushdown(t);
        while (!isroot(t)) {
          int f = fat[t];
          int g = fat[f];
          if (isroot(f))
    	      rotate(t);
          else {
    	      int a = f && son[f][1] == t;
    	      int b = g && son[g][1] == f;
    	      if (a == b)
    	        rotate(f), rotate(t);
    	      else
    	        rotate(t), rotate(t);
          }
        }
      }
    
      inline void access(int t) {
        for (int p = 0; t; p = t, t = fat[t])
          splay(t), son[t][1] = p, update(t);
      }
    
      inline void makeroot(int t) {
        access(t), splay(t), rev[t] ^= 1;
      }
    
      inline int find(int t) {
        access(t), splay(t);
        while (son[t][0])
          t = son[t][0];
        return t;
      }
    
      inline void link(int t, int f) {
        makeroot(t), fat[t] = f;
      }
    
      inline void cut(int a, int b) {
        makeroot(a), access(b), splay(b);
        if (son[b][0] == a)
          son[b][0] = fat[a] = 0, update(b);
      }
    
      inline void preworkNTR(void) {
        for (int i = 1; i <= n; ++i)
          val[i] = min[i] = inf;
        for (int i = 1; i <= m; ++i) {
          if (E[i].x == E[i].y) {
            ntr[i] = m;
            continue;
          }
          if (find(E[i].x) == find(E[i].y)) {
    	      makeroot(E[i].x);
    	      access(E[i].y);
    	      splay(E[i].y);
    	      ntr[i] = min[E[i].y];
    	      cut(E[ntr[i]].x, ntr[i] + n);
    	      cut(E[ntr[i]].y, ntr[i] + n);
          }
          val[i + n] = min[i + n] = i;
          link(E[i].x, i + n);
          link(E[i].y, i + n);
        }
      }
    }
    
    namespace CMT {
      const int K = 25;
    
      int tot = 0;
      int sum[K * mxn];
      int lsn[K * mxn];
      int rsn[K * mxn];
      int rot[K * mxn];
    
      void insert(int &t, int p, int l, int r, int v) {
        t = ++tot;
        lsn[t] = lsn[p];
        rsn[t] = rsn[p];
        sum[t] = sum[p] + 1;
        if (l == r)return;
        int mid = (l + r) >> 1;
        if (v <= mid)
          insert(lsn[t], lsn[p], l, mid, v);
        else
          insert(rsn[t], rsn[p], mid + 1, r, v);
      }
    
      int query(int t, int l, int r, int x, int y) {
        if (!t)return 0;
        if (l == x && r == y)
          return sum[t];
        int mid = (l + r) >> 1;
        if (y <= mid)
          return query(lsn[t], l, mid, x, y);
        else if (x > mid)
          return query(rsn[t], mid + 1, r, x, y);
        else
          return query(lsn[t], l, mid, x, mid) + query(rsn[t], mid + 1, r, mid + 1, y);
      }
      
      inline void preworkNTR(void) {
        for (int i = 1; i <= m; ++i)
          insert(rot[i], rot[i - 1], 0, m, ntr[i]);
      }
    
      inline int solve(int l, int r) {
        return n - query(rot[r], 0, m, 0, l - 1) + query(rot[l - 1], 0, m, 0, l - 1);
      }
    }
    
    signed main(void) {
      n = nextInt();
      m = nextInt();
      q = nextInt();
      e = nextInt();
      for (int i = 1; i <= m; ++i)
        E[i].x = nextInt(),
        E[i].y = nextInt();
      LCT::preworkNTR(); 
      CMT::preworkNTR();
      int lastans = 0;
      for (int i = 1; i <= q; ++i) {
        int L = nextInt();
        int R = nextInt();
        if (e)
          L ^= lastans,
          R ^= lastans;
        printf("%d
    ", lastans = CMT::solve(L, R));
      }
    }
    

      

    @Author: YouSiki

  • 相关阅读:
    HDU_2030——统计文本中汉字的个数
    HDU_2028——求多个数的最小公倍数
    HDU_2027——统计元音
    HDU_2026——将单词的首字母变大写
    HDU_2025——查找最大的字母
    HDU_2024——判断字符串是否是c语言合法标识符
    HDU_2023——求平均成绩
    HDU_2022——海选女主角
    HDU_2021——最少RMB问题
    HDU_2020——按绝对值排序
  • 原文地址:https://www.cnblogs.com/yousiki/p/6399402.html
Copyright © 2020-2023  润新知