www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
这题做法很多。 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
这个方法实际上就是上面那个方法的改进版.其他细节都一样.因为我们发现既然都已经用了链表了,就没有必要再模拟它的过程一个一个将 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
这种方法非常显然,直接利用特性翻转模拟即可.复杂度控制在 O ( n l o g n ) O(nlogn) O(nlogn).
代码见代码仓库4.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;
}
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;
}
#include
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;
}