HNCPC2019-K-双向链表练习题(好题)

前言

这题做法很多。 1.双端队列 + 启发式合并. 2.List 3.无向图模拟 4.splay.5.treap

题目大意

链接

方法一:双端队列 + 启发式合并

题目看起来就是个大模拟.发现关键点:拼接完之后会整体反转.那么我们自然想到了用双端队列,维护一个镜像即可(思路可见this)。但是遇到了第一个问题:卡空间.那么我们不能直接用 d e q u e deque deque.有两种解决方法:
1.手写双端队列,动态开内存且每次及时回收 L b i L_{b_i} Lbi的内存.
2.使用List代替 d e q u e deque deque.因为我们不需要 O ( 1 ) O(1) O(1)的随机存取队列。所以用链表实现双端队列是一样的。而且使用的内存空间小很多。因为链表会动态的申请和销毁节点.

第二个问题:超时.

这么模拟严格来讲可以将复杂度卡到 O ( n 2 ) O(n^2) O(n2).但是我们发现每次是将一个链表拼接到另一个链表,并且拼接的链表会被清空.那么意味着整个过程总节点数是不变的.那么自然我们可以想到启发式合并.复杂度 O ( n l o g n ) O(nlogn) O(nlogn).证明过程类似并查集的启发式合并.

然后还需要注意一个问题:
操作是有方向性的.如果实际是大sz 合并到 小sz中.我们得反着来.所以还得映射一下索引.

i d ( i ) id(i) id(i)代表第 i i i个队列实际存储在下标为 i d ( i ) id(i) id(i)的队列中.上面那种情况我们就得 s w a p ( i d ( 小 的 ) , i d ( 大 的 ) ) swap(id(小的) , id(大的)) swap(id(),id()).

代码见代码仓库1.1

方法二:List模拟

这个方法实际上就是上面那个方法的改进版.其他细节都一样.因为我们发现既然都已经用了链表了,就没有必要再模拟它的过程一个一个将 L b i L_{b_i} Lbi取出来再放到 L a i L_{a_i} Lai里去了.可以直接将表头转接一下就好了.

所以还是对每个链表维护一个镜像版本.然后根据题目的那个操作的特性稍微讨论一下就好了.

复杂度: O ( n ) O(n) O(n).

这里学习到一个新的STL函数: s p l i c e splice splice,其作用是 O ( 1 ) O(1) O(1)时间完成链表的拼接.并且将拼接的链表删除.

用法:x.splice(x.end() , y) – 使用后x = x + y, y = empty

代码见代码仓库2.1

方法三:无向图dfs模拟(待补)
方法四:splay/fhqTreap解法

这种方法非常显然,直接利用特性翻转模拟即可.复杂度控制在 O ( n l o g n ) O(nlogn) O(nlogn).

代码见代码仓库4.1

代码仓库

1.1
list<int> q[maxn][2];
bool tag[maxn];
int id[maxn];
int main()
{
    
    
    int n , m;
    while (~scanf("%d%d" , &n , &m)){
    
    
        for (int i = 1 ; i <= n ; i++){
    
    
            q[i][0].clear();
            q[i][1].clear();
            tag[i] = 1;
            q[i][0].push_back(i);
            q[i][1].push_front(i);
            id[i] = i;
        }
        for (int i = 1 ; i <= m ; i++){
    
    
            int x , y; read(x);read(y);
            int c = id[x];
            int d = id[y];
            // 启发式合并
            if (q[d][tag[d]].size() > q[c][tag[c]].size()){
    
    
                tag[d] = !tag[d];
                while (q[c][tag[c]].size()){
    
    
                    q[d][tag[d]].push_back(q[c][tag[c]].back());
                    q[c][tag[c]].pop_back();

                    q[d][!tag[d]].push_front(q[c][!tag[c]].front());
                    q[c][!tag[c]].pop_front();
                }
                swap(id[x] , id[y]);
            }else {
    
    
                while (q[d][tag[d]].size()) {
    
    
                    q[c][tag[c]].push_back(q[d][tag[d]].front());
                    q[d][tag[d]].pop_front();

                    q[c][!tag[c]].push_front(q[d][!tag[d]].back());
                    q[d][!tag[d]].pop_back();
                }
                tag[c] = !tag[c];
            }
        }
        printf("%d " , q[id[1]][tag[id[1]]].size());
        while (q[id[1]][tag[id[1]]].size()){
    
    
            printf("%d " , q[id[1]][tag[id[1]]].front());
            q[id[1]][tag[id[1]]].pop_front();
        }
        printf("\n");
    }
    return 0;
}
2.1
list<int> q[maxn][2];
int main()
{
    
    
    int n , m;
    while (~scanf("%d%d" , &n , &m)){
    
    
        for (int i = 1 ; i <= n ; i++){
    
    
            q[i][0].clear();
            q[i][1].clear();
            q[i][0].push_back(i);
            q[i][1].push_back(i);
        }
        for (int i = 1 ; i <= m ; i++){
    
    
            int x , y; read(x);read(y);
            q[y][0].splice(q[y][0].end() , q[x][0]);
            q[x][1].splice(q[x][1].end() , q[y][1]);
            swap(q[y][0] , q[x][0]);
            swap(q[x][0] , q[x][1]);
            q[y][0].clear();
            q[y][1].clear();
        }
        printf("%d " , q[1][1].size());
        while (q[1][1].size()){
    
    
            printf("%d " , q[1][1].front());
            q[1][1].pop_front();
        }
        printf("\n");
    }
    return 0;
}

3.1
4.1
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
struct Node
{
    
    
    int l , r , val , key , sz;
    bool re;
}fhq[maxn];
int cnt , rt[maxn];
mt19937 rnd(233);
int newnode (int val)
{
    
    
    fhq[++cnt].val = val;
    fhq[cnt].sz = 1;
    fhq[cnt].key = rnd();
    fhq[cnt].l = fhq[cnt].r = fhq[cnt].re = 0;
    return cnt;
}
void pushup (int x){
    
    
    fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;
}
void pushdown (int x){
    
    
    if (!fhq[x].re) return ;
    swap(fhq[x].l , fhq[x].r);
    fhq[x].re = 0;
    fhq[fhq[x].l].re ^= 1;
    fhq[fhq[x].r].re ^= 1;
    return ;
}
// 将now这个子树按sz分成两个部分,sz部分接在x,大于部分接在y
void split (int now , int sz , int &x , int &y)
{
    
    
    if (!now) {
    
    
        x = y = 0;
        return ;
    }
    pushdown(now);
    if (fhq[fhq[now].l].sz < sz){
    
    
        x = now;
        split(fhq[now].r , sz - fhq[fhq[now].l].sz - 1 , fhq[now].r , y);
    }else {
    
    
        y = now;
        split(fhq[now].l , sz , x , fhq[now].l);
    }
    pushup(now);
}
int mer (int x , int y)
{
    
    
    if (!x || !y) return x + y;
    if (fhq[x].key > fhq[y].key){
    
    
        pushdown(x);
        fhq[x].r = mer(fhq[x].r , y);
        pushup(x);
        return x;
    }
    pushdown(y);
    fhq[y].l = mer(x , fhq[y].l);
    pushup(y);
    return y;
}
void dfs (int now)
{
    
    
    if (!now) return ;
    pushdown(now);
    dfs(fhq[now].l);
    printf("%d " , fhq[now].val);
    dfs(fhq[now].r);
    return ;
}
int main()
{
    
    
    int n , m;
    while (~scanf("%d%d" , &n , &m)){
    
    
        cnt = 0;
        for (int i = 1 ; i <= n ; i++){
    
    
            rt[i] = 0;
            rt[i] = mer(rt[i] , newnode(i));
        }
        for (int i = 1 ; i <= m ; i++){
    
    
            int x , y; scanf("%d%d" , &x , &y);
            rt[x] = mer(rt[x] , rt[y]);
            fhq[rt[x]].re ^= 1;
            rt[y] = 0;
        }
        printf("%d " , fhq[rt[1]].sz);
        dfs(rt[1]);
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/114919560
今日推荐