【ACM】 2019湖南省赛K(牛客国庆集训Day1 K) 双向链表练习题

放上题目链接:https://ac.nowcoder.com/acm/contest/1099/K

中文题面不做过多解释。

比赛刚结束的时候和队友讨论过这道题,当时说的思路是用双向链表把第一个串的尾和第二个串的头连起来,建立一个数组存状态。每次操作都反转一下第一个串的状态。这个状态数组表示的是下一次是连表头还是表尾。

然而时间太久,下午模拟了一下,成功把自己绕进去。(雾...)

写这篇题解只是想记录一下之前不知道的一个STL list的用法。

对每个链表,同时记录它的正序li和倒序dli。

那么对于一次操作a b,dli b+dli a即为新链表a的正序(前面都是倒序的),li a+ li b为新链表a的倒序。

通过splice()这个函数可以实现链表的拼接。

函数有以下三种声明:

一:void splice ( iterator position, list<T,Allocator>& x );  

二:void splice ( iterator position, list<T,Allocator>& x, iterator it );

三:void splice ( iterator position, list<T,Allocator>& x, iterator first, iterator last );

解释:

position 是要操作的list对象的迭代器

list<T Allocator>&x 被剪的对象

对于一:会在position后把list<T Allocator>&x所有的元素到剪接到要操作的list对象

对于二:只会把it的值剪接到要操作的list对象中

对于三:把first 到 last 剪接到要操作的list对象中
(此处引用自:https://blog.csdn.net/Wchenchen0/article/details/83058928

时间复杂度为O(n),但是此时size()处理时间不为O(n)

(详见:https://blog.csdn.net/russell_tao/article/details/8572000 )

放上此题代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
list <int> li[maxn],dli[maxn];
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n;i++)
		{
			li[i].clear();
			li[i].push_back(i);
			dli[i].clear();
			dli[i].push_back(i);
		}
		int a,b;
		while(m--)
		{
			scanf("%d%d",&a,&b);
			dli[b].splice(dli[b].end(),dli[a]);
			li[a].splice(li[a].end(),li[b]);
			swap(dli[a],li[a]);
			swap(li[a],dli[b]);
			li[b].clear();
			dli[b].clear();
		}
		cout<<li[1].size();
		for(list <int>::iterator iter=li[1].begin();iter!=li[1].end();iter++)
		cout<<" "<<*iter;
		cout<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41279172/article/details/102002922