zoukankan      html  css  js  c++  java
  • [HNOI2012]永无乡

    嘟嘟嘟


    这道题刚开始想lct,但后来发现并没有那么麻烦。


    其实就是splay + 启发式合并,同时用并查集维护连通性……
    刚开始每一个节点都属于一个splay以及一个并查集,合并的时候把小的splay拆散,往大的上一个一个添加。
    因为每一次splay至少会变大一倍,所以每一个点最多被合并(log n)次,因此启发式合并为(O(n log n))的。


    剩下的就是细节了:启发式合并前,我们要找到(x, y)所在的并查集的代表元,然后代表元所在的splay的根才是(x, y)所在splay的根。接下来再合并root[px]和root[py]所在splay。
    自己没怎么写懂,最后不得不参考了一下yyb大佬的代码,他先把所有点的所在splay根节点都赋成了(n + i),然后用这个判断是否为每一个splay的根。我大体上是理解了,但是细节还是有点蒙。
    附上yyb大神的题解

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 5e5 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, m, pos[maxn];
    char c[2];
    struct Tree
    {
      int ch[2], fa;
      int siz, val;
    }t[maxn];
    int root[maxn], tcnt = 0;
    
    int p[maxn];
    In int Find(int x)
    {
      return x == p[x] ? x : p[x] = Find(p[x]);
    }
    In void pushup(int now)
    {
      t[now].siz = t[t[now].ch[0]].siz + t[t[now].ch[1]].siz + 1;
    }
    In void rotate(int x)
    {
      int y = t[x].fa, z = t[y].fa, k = (t[y].ch[1] == x);
      t[z].ch[t[z].ch[1] == y] = x; t[x].fa = z;
      t[y].ch[k] = t[x].ch[k ^ 1]; t[t[x].ch[k ^ 1]].fa = y;
      t[x].ch[k ^ 1] = y; t[y].fa = x;
      pushup(y), pushup(x);
    }
    In void splay(int x, int s)
    {
      while(t[x].fa != s)
        {
          int y = t[x].fa, z = t[y].fa;
          if(z != s) rotate(((t[y].ch[0] == x) ^ (t[z].ch[0] == z)) ? x : y);
          rotate(x);
        }
      if(s <= n) root[s] = x;  //不太懂……
    }
    In void insert(int x, int y)
    {
      int now = root[y], fa = y;
      while(now && t[now].val != x) fa = now, now = t[now].ch[x > t[now].val];
      now = ++tcnt;
      t[now].fa = fa; t[now].siz = 1;
      t[now].ch[0] = t[now].ch[1] = 0;
      if(fa > n) t[fa].ch[x > t[fa].val] = now;  //这也是……
      t[now].val = x;
      splay(now, y);
    }
    In void dfs(int now, int id)
    {
      if(t[now].ch[0]) dfs(t[now].ch[0], id);
      if(t[now].ch[1]) dfs(t[now].ch[1], id);
      insert(t[now].val, id);
    }
    In void merge(int x, int y)
    {
      int px = Find(x), py = Find(y);
      if(px == py) return;
      if(t[root[px]].siz > t[root[py]].siz) swap(px, py);
      p[px] = py;
      dfs(root[px], py);
    }
    In int query(int x, int k)
    {
      int now = root[x];
      if(t[now].siz < k) return -1;
      while(1)
        {
          if(t[t[now].ch[0]].siz >= k) now = t[now].ch[0];
          else if(t[t[now].ch[0]].siz + 1 == k) return t[now].val;
          else k -= (t[t[now].ch[0]].siz + 1), now = t[now].ch[1];
        }
    }
    
    
    int main()
    {
      n = read(); m = read();
      for(int i = 1; i <= n; ++i) root[i] = i + n, p[i] = i;
      tcnt = n + n;
      for(int i = 1; i <= n; ++i)
        {
          int x = read(); pos[x] = i; t[i + n].siz = 1;
          t[i + n].val = x; t[i + n].fa = i;
        }
      for(int i = 1, x, y; i <= m; ++i) x = read(), y = read(), merge(x, y);
      m = read();
      for(int i = 1; i <= m; ++i)
        {
          scanf("%s", c); int x = read(), y = read();
          if(c[0] == 'B') merge(x, y);
          else
    	{
    	  int ans = query(Find(x), y);
    	  write(ans == -1  ? ans : pos[ans]), enter;
    	}
        }
      return 0;
    }
    
  • 相关阅读:
    fs.readdirSync
    symbol
    vuex-count
    webpack2.0
    关于vuex报错
    store
    .NET MVC 验证码
    SQLServer 加密
    IE10、IE11下SCRIPT5009: “__doPostBack”未定义
    Sql Server 增加字段、修改字段、修改类型、修改默认值
  • 原文地址:https://www.cnblogs.com/mrclr/p/10175775.html
Copyright © 2011-2022 走看看