原题链接:https://vjudge.net/problem/UVA-12657
分类:链表
备注:双向循环链表
都是看着紫书的提示和一些比较关键的代码才一步步做出来的。
这应该算是个好题吧,链表的使用要注意的细节很多。
要注意初始化成一个双向循环链表,这样保证每次调换位置和头尾相关时不会出现错误,以0为哨位节点以便于计算ans时要进行的遍历操作。
link函数连接两个结点,关键是要每次执行命令之前把X,Y的左右结点存储下来,在此基础上使用link函数可以使得代码变得简单易懂,也不容易犯错。
计算ans时,先计数再判断奇偶性的这种操作是最好的,奇数两种顺序算结果相同,偶数则要错位一下。如果直接通过是否反转去计算的答案是错的。
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int L[maxn], R[maxn];
void link(int lef, int rig) {
R[lef] = rig; L[rig] = lef;
}
int main(void) {
int n, m, kase = 0;
while (~scanf("%d %d", &n, &m)) {
for (int i = 1; i <= n; i++) {//0为哨位节点,构建循环双向链表
L[i] = i - 1;
R[i] = (i + 1) % (n + 1);
}
R[0] = 1; L[0] = n;
bool rev = 0;//反转标记
for (int i = 0; i < m; i++) {
int cmd; scanf("%d", &cmd);
if (cmd == 4) { rev = !rev; continue; }
int X, Y;
scanf("%d %d", &X, &Y);
int LX = L[X], RX = R[X], LY = L[Y], RY = R[Y];
if (cmd < 3) {
if (rev)cmd = 3 - cmd;
if (cmd == 1 && L[Y] != X) {
link(LX, RX); link(LY, X); link(X, Y);
}
else if (cmd == 2 && R[Y] != X) {
link(LX, RX); link(X, RY); link(Y, X);
}
}
else if (cmd == 3) {
if (L[Y] == X) {
link(LX, Y); link(X, RY); link(Y, X);
}
else if (R[Y] == X) {
link(LY, X); link(Y, RX); link(X, Y);
}
else {
link(LY, X); link(X, RY);
link(LX, Y); link(Y, RX);
}
}
}
long long ans = 0;
for (int i = 1, b = 0; i <= n; i++) {
b = R[b];
if (i % 2 == 1) ans += b;
}
if (rev && n % 2 == 0)ans = (1LL * n * (1LL * n + 1)) / 2 - ans;//仅有n为偶数时要换算
printf("Case %d: %lld\n", ++kase, ans);
}
return 0;
}