uva12657-题解
题干
你有n个盒子在桌子上的一条线上从左到右编号为1……n。你的任务是模拟四种操作
1 X Y 移动盒子编号X到盒子编号Y的左边(如果X已经在Y的左边了就忽略)
2 X Y 移动盒子编号X到盒子编号Y的右边(如果X已经在Y的右边了就忽略)
3 X Y 交换盒子编号X与盒子编号Y的位置
4 将整条线反转
操作保证合法,X不等于Y
输入
最多有10组数据,每个数据会包含两个整数n,m(1≤n,m<100,000), 接下来是m行数据,表示操作。
输出
对于每组数据,输出他们奇数位置的编号的和。
思路
对于一串数,我们需要频繁的插入移动数据,宜使用双向链表,(详见双向链表)
这里头节点序号是0,是为了方便init里面for循环也满足
思路很简单,写出每个操作的函数即可,有:
move(o1),删除x左右两个节点和x的关系,并让x和y,y左边节点链接(4个指针操作)
enchange(o1),特殊讨论相邻情况(没讨论会导致自身指针,TLE原因之一),不相邻记录x,y两边节点,交换关系(4*2次指针操作)
reverse(on),从第一个节点开始,交换左右指针,交换完了,此时除了头尾节点都成功翻转,之后更新头尾节点及其相邻指向即可。
值得注意的是,出现多次TLE,排除了循环和自身指针的情况,我们考虑算法时间复杂度的问题
由于move,exchange,都是o1复杂度,我们考虑优化reverse();
注意到一串数进行反转操作,在进行x插入到y左边,等同于x插入到y右边,再进行反转
也就是反转操作可以提后,放在最后再抵消!然后输出奇数位,如果反转,只需要倒着输出即可
所以我们甚至不用写reverse函数!
只需要一个reversed标志,如果为true,执行假定反转的操作即可
修改逻辑,取消reverse,ac
代码实现
#include<iostream>
#include<sstream>
using namespace std;
const int MAXN=100010;
void init(int n);
void insert(int a,int num);
void delete_(int a);
void move1(int x,int y);
void move2(int x,int y);
void exchange(int x,int y);
int idx=2;
int l[MAXN],r[MAXN],e[MAXN];
bool reversed=false;
int main(){
int n,m;
int times=0;
while(cin>>n>>m){
times++;
idx=2;
r[1]=0,l[0]=1;
init(n);
int j=m;
reversed=false;
while(j--){
int num,x,y;
scanf("%d",&num);
if(num!=4)scanf("%d %d",&x,&y);
switch(num){
case 1:if(reversed){move2(x+1,y+1);break;}else{move1(x+1,y+1);break;}
case 2:if(reversed){move1(x+1,y+1);break;}else{move2(x+1,y+1);break;}
case 3:exchange(x+1,y+1);break;
case 4:reversed=!reversed;break;
}
}
long long sum=0;
bool add = true;
if(!reversed)for(int i = r[1]; i != 0; i = r[i]){
if(add) sum += e[i];
add = !add;
}
else{
for(int i = l[0]; i != 1; i = l[i]){
if(add) sum += e[i];
add = !add;
}
}
cout<<"Case "<<times<<": "<<sum<<endl;
}
return 0;
}
void init(int n){
for(int i=1;i<=n;i++)
insert(i,i);
//编号i节点插入的是i-1
}
void insert(int a,int num){
//在a后插入
e[idx]=num;
l[idx]=a,r[idx]=r[a];
l[r[a]]=idx,r[a]=idx;
idx++;
}
void delete_(int a){
if(a==0||a==1)return;
r[l[a]]=r[a];
l[r[a]]=l[a];
}
void move1(int x,int y){
if(x==l[y])return ;
delete_(x);
int z=l[y];
l[x]=z,r[x]=y;
r[z]=x,l[y]=x;
}
void move2(int x,int y){
if(x==r[y])return ;
delete_(x);
int z=r[y];
l[x]=y,r[x]=z;
r[y]=x,l[z]=x;
}
void exchange(int x,int y){
if (r[x] == y) {
int lx = l[x], ry = r[y];
r[lx] = y; l[y] = lx;
r[y] = x; l[x] = y;
r[x] = ry; l[ry] = x;
return ;
}
else if (r[y] == x) {
exchange(y, x); // 直接调用上面情况
return ;
}
int lx=l[x],rx=r[x];
int ly=l[y],ry=r[y];
l[x]=ly,r[x]=ry;
r[ly]=x;l[ry]=x;
l[y]=lx,r[y]=rx;
r[lx]=y,l[rx]=y;
}

浙公网安备 33010602011771号