题目:https://vjudge.net/problem/UVA-12657
思路:题目很短也很好理解,但题目时限要求较高,uva上的题目时限大多是3s,这题1s,起初我用STL的list容器做果不其然超时了,刘汝佳给出的双向链表的数组实现又实在是晦涩难懂,即便看懂了我也没能力独立写出来。STL list超时的主要原因是查询元素的时间代价太大,停滞了两天后我突然想到可以用一个指针数组下标存值来辅助建立传统双向链表,这样就通过下标可以直接访问指向链表节点的元素,完全省略了查找过程。话是这么说,但双向链表的操作异常繁琐,需要处处小心。
还有一些技巧,书中已经提到了,比如利用标记记录链表是否逆序,而并不反转指针方向,借以提高运行效率。
代码:C++
#include <iostream>
#include <cstdio>
#include <list>
#include <algorithm>
using namespace std;
const int maxn = 100000+10;
struct List
{
int value;
List *next;
List *prevous;
List(int i):value(i){}
};
List *data[maxn] = {NULL};
List *first;
List *last;
bool isreversed;
void creatList(int n)
{
data[0] = NULL;
for(int i = 1; i<=n; i++)
{
data[i] = new List(i);
data[i]->prevous = data[i-1];
}
for(int i = 1; i<=n-1; i++)
{
data[i]->next = data[i+1];
}
data[n]->next = NULL;
first = data[1];
last = data[n];
}
void clearList(int n)
{
first = NULL;
last = NULL;
for(int i = 1; i<=n; i++)
{
delete data[i];
data[i] = NULL;
}
}
void removelink(int x)
{
if(last==data[x])
{
data[x]->prevous->next = NULL;
last = data[x]->prevous;
}
else if(first==data[x])
{
first = data[x]->next;
data[x]->next->prevous = NULL;
}
else
{
data[x]->prevous->next = data[x]->next;
data[x]->next->prevous = data[x]->prevous;
}
}
void moveleft(int x, int y)
{
if(data[y]->prevous==data[x])
{
return;
}
removelink(x);
if(first==data[y])
{
first = data[x];
data[x]->prevous = NULL;
data[x]->next = data[y];
data[y]->prevous = data[x];
}
else
{
data[y]->prevous->next = data[x];
data[x]->next = data[y];
data[x]->prevous = data[y]->prevous;
data[y]->prevous = data[x];
}
}
void moveright(int x, int y)
{
if(data[y]->next==data[x])
{
return;
}
removelink(x);
if(last==data[y])
{
data[y]->next = data[x];
data[x]->prevous = data[y];
last = data[x];
data[x]->next = NULL;
}
else
{
data[y]->next->prevous = data[x];
data[x]->next = data[y]->next;
data[y]->next = data[x];
data[x]->prevous = data[y];
}
}
void swapbox(int x, int y)
{
if(first==data[x])
{
int rightx = data[x]->next->value;
moveright(x, y);
if(y!=rightx)
moveleft(y, rightx);
}
else
{
int leftx = data[x]->prevous->value;
moveleft(x, y);
if(y!=leftx)
moveright(y, leftx);
}
}
void solve(int order, int x, int y)
{
if(!isreversed)
{
switch(order)
{
case 1: moveleft(x, y); break;
case 2: moveright(x, y); break;
case 3: swapbox(x, y); break;
case 4: isreversed = !isreversed; break;
}
}
else
{
switch(order)
{
case 1: moveright(x, y); break;
case 2: moveleft(x, y); break;
case 3: swapbox(x, y); break;
case 4: isreversed = !isreversed; break;
}
}
}
long long getoddsum()
{
long long sum = 0;
if(!isreversed)
{
List *p;
int i = 1;
for(p = first; p!=NULL; p = p->next, i++)
{
if(i%2==1)
{
sum += p->value;
}
}
}
else
{
List *p;
int i = 1;
for(p = last; p!=NULL; p = p->prevous, i++)
{
if(i%2==1)
{
sum += p->value;
}
}
}
return sum;
}
int main()
{
int n, m, serial = 1;
int order, x, y;
while(scanf("%d%d", &n, &m)!=EOF)
{
creatList(n);
isreversed = false;
while(m--)
{
scanf("%d", &order);
if(order!=4)
scanf("%d%d", &x, &y);
solve(order, x, y);
}
printf("Case %d: %lld\n", serial++, getoddsum());
clearList(n);
}
return 0;
}