前言
scy说要我和FYC去负责一套CEOI
然后我被分到CEOI2013
然后要有题解和中文翻译还有标程QAQ
现在我只水了三题。。
水了两天,在这里感谢LHY对我英语上的巨大帮助
题面什么的我已经翻译好了,在caioj,但是题目似乎并不会这么快放出来
现在这里存一下题解吧
D1T2 TRAM
这题是我自己yy的做法,不知道标解是什么,但反正能过,不喜欢我的可以自己去看英文题解
这道题我们不难想到一个最短距离肯定是在两行中间的人
如果行数之差为奇数就处理一行,反之两行
其实如果你分类讨论是可以处理少一点的,但是多一点你也不会T对吧
然后呢,你就可以维护一个链表,表示哪些行上边有人
删除和加入就暴力弄就好了,反正是链表
然后每次枚举相邻的两个行,看看他们中间的到他们最优距离是多少
然后如果是1的话,说明还可以在同一行,列数不同,然后你就再扫一次,看看有没有解
然后还有一种特殊的地方就是第一行和最后一行
这个复杂度是O(m*n)的,期望得分70分
代码我写了,如果觉得理解不好可以看一看
由于细节什么的蛮多,于是我写了 一早上+一晚上
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX=1<<30;
const int N=150005;
const int M=150005;
int n,m;
struct qq
{
int next,last;
int c[2];//第一行是哪一个客人 第二行是哪一个客人
qq ()
{
next=last=0;
c[0]=c[1]=-1;
};
}s[N];//我的链表只储存每一行连接的
int cnt=0;//现在有多少行有人
int a[M],tot=0;
void print (int x)//输出这个人
{
int now=a[x];
if (s[now].c[0]==x) printf("%d %d\n",now,1);
else printf("%d %d\n",now,2);
}
int get_dis (int x1,int y1,int x2,int y2) {return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);}
void Ins (int x,int A,int B)//插在第x行后面 位置时(a,b)
{
// printf("HA:%d %d %d %d\n",x,A,B,tot);
s[A].c[B]=tot;
if (s[A].c[B^1]!=-1)//这一行之前有人
return ;
cnt++;
s[A].last=x;
s[A].next=s[x].next;
s[s[x].next].last=A;
s[x].next=A;
}
void Del (int A,int B)//这个人离开了
{
s[A].c[B]=-1;
if (s[A].c[B^1]!=-1)//这一行是两个人的
return ;
cnt--;
int Last=s[A].last,Next=s[A].next;
s[Last].next=Next;s[Next].last=Last;
}
int aa,bb,ans;//坐标
void update (int xx,int yy,int zz)
{
//printf("NO:%d %d %d\n",xx,yy,zz);
if (zz>ans)
{
ans=zz;aa=xx;bb=yy;
return ;
}
if (zz==ans&&xx<aa)
{
ans=zz;aa=xx;bb=yy;
return ;
}
if (zz==ans&&xx==aa&&yy<bb)
{
ans=zz;aa=xx;bb=yy;
return ;
}
return ;
}
void compare (int x,int y,int A)//这两行中间 比较这一行两个点的最优值
{
int d0=MAX,d1=MAX;
if (x!=0&&s[x].c[0]!=-1) d0=min(d0,get_dis(x,0,A,0));
if (x!=0&&s[x].c[1]!=-1) d0=min(d0,get_dis(x,1,A,0));
if (y!=n+1&&s[y].c[0]!=-1) d0=min(d0,get_dis(y,0,A,0));
if (y!=n+1&&s[y].c[1]!=-1) d0=min(d0,get_dis(y,1,A,0));
if (x!=0&&s[x].c[1]!=-1) d1=min(d1,get_dis(x,1,A,1));
if (x!=0&&s[x].c[0]!=-1) d1=min(d1,get_dis(x,0,A,1));
if (y!=n+1&&s[y].c[1]!=-1) d1=min(d1,get_dis(y,1,A,1));
if (y!=n+1&&s[y].c[0]!=-1) d1=min(d1,get_dis(y,0,A,1));
update(A,0,d0);update(A,1,d1);
return ;
}
int main()
{
scanf("%d%d",&n,&m);
s[0].last=-1;s[0].next=n+1;
s[n+1].last=0;s[n+1].next=n+2;
while (m--)
{
char ss[5];
scanf("%s",ss);
if (ss[0]=='E')//来了一个人
{
if (cnt==n)//如果每一行起码有一个人
{
for (int u=1;u<=n;u++)
{
if (s[u].c[0]==-1) {a[++tot]=u;Ins(u-1,u,0);break;}
if (s[u].c[1]==-1) {a[++tot]=u;Ins(u-1,u,1);break;}
}
}
else if (cnt==0)//现在一个人也没有
{
a[++tot]=1;
Ins(0,1,0);
}
else//有人,但不满
{
ans=0;
aa=MAX;bb=MAX;
if (s[0].next!=1)//第一行没有人
compare(0,s[0].next,1);//在哪个比较优
if (s[n+1].last!=n)//最后一行没有人
compare(s[n+1].last,n+1,n);
for (int u=s[0].next;u!=s[n+1].last;u=s[u].next)
{
int l=u,r=s[l].next;
if ((r-l)%2==0)//奇数
compare(l,r,(l+r)>>1);
else
{
compare(l,r,(l+r)>>1);
compare(l,r,(l+r+1)>>1);
}
}
// printf("ooo:%d %d %d\n",aa,bb,ans);
if (ans<=1)
{
for (int u=s[0].next;u!=n+1;u=s[u].next)
{
if (aa<=u) break;
if (s[u].c[0]==-1)//这个位置时空的
{
aa=u;bb=0;
break;
}
if (s[u].c[1]==-1)//这个位置时空的
{
aa=u;bb=1;
break;
}
}
}
// printf("K:%d %d\n",aa,bb);
a[++tot]=aa;
for (int u=0;u!=n+1;u=s[u].next)
{
int l=u,r=s[l].next;
//printf("FYC:%d %d\n",l,r);
if (l<=aa&&r>=aa)
{
//printf("OZY:%d %d %d\n",l,aa,bb);
Ins(l,aa,bb);
break;
}
}
}
print(tot);
}
else//走了一个人
{
tot++;
int x;
scanf("%d",&x);
int now=a[x];
if (s[now].c[0]==x) Del(now,0);
else Del(now,1);
}
// printf("YES:%d\n",cnt);
/*for (int u=0;u<=n+1;u++)
printf("%d:%d %d\n",u,s[u].c[0],s[u].c[1]);*/
}
return 0;
}
我们考虑对上面的算法进行优化,就是说每一次扫太慢了,因为有很多信息是不会变的,可以用之前的结果来代替这个龟速的枚举
那么我们就想,有什么东西可以支持修改和查询最小值呢?
没错,就是set
我们就维护一个set表示两行之间的答案就可以了
然后插入和删除就暴力重构一下有变化的地方,再把它丢进去就好了。。
感觉蛮简单的。。大家应该都能懂吧
#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
typedef long long LL;
const LL MAX=1LL<<55;
const int N=150005;
const int M=150005;
int n,m;
struct qq
{
int next,last;
int c[2];//第一行是哪一个客人 第二行是哪一个客人
qq ()
{
next=last=0;
c[0]=c[1]=-1;
};
}s[N];//我的链表只储存每一行连接的
int cnt=0;//现在有多少行有人
int a[M],tot=0;
set<int> S; //当前至少有一个位置是空的地方
set<int>::iterator it;
set<pair<LL,int> > SS;//最优解
set<pair<LL,int> >::iterator It;
struct qt
{
int a,b;
LL ans;//两个坐标 ans
}g[N];//如果这个点存在的话,就更新这三个东西
void print (int x)//输出这个人
{
int now=a[x];
if (s[now].c[0]==x) printf("%d %d\n",now,1);
else printf("%d %d\n",now,2);
}
LL get_dis (int x1,int y1,int x2,int y2) {return (LL)(x2-x1)*(x2-x1)+(LL)(y2-y1)*(y2-y1);}
int aa,bb,ans_l;
LL ans;//坐标
void update (int xx,int yy,LL zz,int l)
{
#define hehe1 {ans=zz;aa=xx;bb=yy;ans_l=l;}
if (zz>ans)
hehe1;
if (zz==ans&&xx<aa)
hehe1;
if (zz==ans&&xx==aa&&yy<bb)
hehe1;
return ;
}
void update1 (int a,int b,LL Dis,int x)
{
//printf("OZY:%d %d %d %d %d\n",a,b,Dis,x,g[x].ans);
#define hehe g[x]=(qt){a,b,Dis};
if (Dis>g[x].ans)
hehe;
if (Dis==g[x].ans&&a<g[x].a)
hehe;
if (Dis==g[x].ans&&a==g[x].a&&b<g[x].b)
hehe;
//printf("FYC:%d %d %d %d %d\n",a,b,Dis,x,g[x].ans);
return ;
}
void compare (int x,int y,int A)//算出这两行里面,最优值
{
if (A<=x||A>=y) return ;
LL d0=MAX,d1=MAX;
if (x!=0&&s[x].c[0]!=-1) d0=min(d0,get_dis(x,0,A,0));
if (x!=0&&s[x].c[1]!=-1) d0=min(d0,get_dis(x,1,A,0));
if (y!=n+1&&s[y].c[0]!=-1) d0=min(d0,get_dis(y,0,A,0));
if (y!=n+1&&s[y].c[1]!=-1) d0=min(d0,get_dis(y,1,A,0));
if (x!=0&&s[x].c[1]!=-1) d1=min(d1,get_dis(x,1,A,1));
if (x!=0&&s[x].c[0]!=-1) d1=min(d1,get_dis(x,0,A,1));
if (y!=n+1&&s[y].c[1]!=-1) d1=min(d1,get_dis(y,1,A,1));
if (y!=n+1&&s[y].c[0]!=-1) d1=min(d1,get_dis(y,0,A,1));
if (d0!=MAX) update1(A,0,d0,x);
if (d1!=MAX) update1(A,1,d1,x);
return ;
}
void K (int u)//重构这个
{
if (u==0||u>=n) return ;
if (SS.count(make_pair(-g[u].ans,u))>0)
SS.erase(make_pair(-g[u].ans,u));
g[u].ans=-1;g[u].a=g[u].b=MAX;
int l=u,r=s[l].next;
if ((r-l)%2==0)//奇数
compare(l,r,(l+r)>>1);
else
{
compare(l,r,(l+r)>>1);
compare(l,r,(l+r+1)>>1);
}
SS.insert(make_pair(-g[u].ans,u));
}
void Ins (int x,int A,int B)//插在第x行后面 位置时(a,b)
{
s[A].c[B]=tot;
if (s[A].c[B^1]!=-1)//这一行之前有人
{
K(x);K(A);
S.erase(A);
return ;
}
cnt++;
s[A].last=x;
s[A].next=s[x].next;
s[s[x].next].last=A;
s[x].next=A;
K(x);K(A);
}
void Del (int A,int B)//这个人离开了
{
s[A].c[B]=-1;
S.insert(A);
if (s[A].c[B^1]!=-1)//这一行是两个人的
{
K(s[A].last);K(A);
return ;
}
SS.erase(make_pair(-g[A].ans,A));g[A].ans=-1;g[A].a=g[A].b=MAX;
cnt--;
int Last=s[A].last,Next=s[A].next;
s[Last].next=Next;s[Next].last=Last;
K(Last);
}
int main()
{
/*freopen("tram.in.8a","r",stdin);
freopen("a.out","w",stdout);*/
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++) S.insert(u);
s[0].last=-1;s[0].next=n+1;
s[n+1].last=0;s[n+1].next=n+2;
while (m--)
{
char ss[5];
scanf("%s",ss);
if (ss[0]=='E')//来了一个人
{
if (cnt==n)//如果每一行起码有一个人
{
it=S.begin();
if (it!=S.end())
{
int u=(*it);
if (s[u].c[0]==-1) {a[++tot]=u;Ins(u-1,u,0);}
if (s[u].c[1]==-1) {a[++tot]=u;Ins(u-1,u,1);}
}
}
else if (cnt==0)//现在一个人也没有
{
a[++tot]=1;
Ins(0,1,0);
}
else//有人,但不满
{
ans=0;
aa=MAX;bb=MAX;
if (s[0].next!=1)//第一行没有人
{
int now=s[0].next;
LL d=MAX;
if (s[now].c[0]!=-1) d=min(d,get_dis(1,0,now,0));
if (s[now].c[1]!=-1) d=min(d,get_dis(1,0,now,1));
update(1,0,d,0);
d=MAX;
if (s[now].c[0]!=-1) d=min(d,get_dis(1,1,now,0));
if (s[now].c[1]!=-1) d=min(d,get_dis(1,1,now,1));
update(1,1,d,0);
}
if (s[n+1].last!=n)//最后一行没有人
{
int now=s[n+1].last;
LL d=MAX;
if (s[now].c[0]!=-1) d=min(d,get_dis(n,0,now,0));
if (s[now].c[1]!=-1) d=min(d,get_dis(n,0,now,1));
update(n,0,d,now);
d=MAX;
if (s[now].c[0]!=-1) d=min(d,get_dis(n,1,now,0));
if (s[now].c[1]!=-1) d=min(d,get_dis(n,1,now,1));
update(n,1,d,now);
}
/*for (int u=s[0].next;u!=s[n+1].last;u=s[u].next)
{
update(g[u].a,g[u].b,g[u].ans,u);
int l=u,r=s[l].next;
if ((r-l)%2==0)//奇数
compare(l,r,(l+r)>>1);
else
{
compare(l,r,(l+r)>>1);
compare(l,r,(l+r+1)>>1);
}
}*/
if (!SS.empty())
{
It=SS.begin();
int u=It->second;
update(g[u].a,g[u].b,g[u].ans,u);
}
if (ans<=1)
{
it=S.begin();
if (it!=S.end())
{
int u=(*it);
if (aa>u)
{
if (s[u].c[0]==-1) {aa=u;bb=0;ans_l=s[u].last;}
else if (s[u].c[1]==-1) {aa=u;bb=1;ans_l=s[u].last;}
}
}
}
//printf("ans:%d %d %d\n",ans_l,aa,bb);
a[++tot]=aa;
Ins(ans_l,aa,bb);
}
print(tot);
}
else//走了一个人
{
tot++;
int x;
scanf("%d",&x);
int now=a[x];
if (s[now].c[0]==x) Del(now,0);
else Del(now,1);
}
/*for (int u=0;u<=n+1;u++)
printf("%d:%d %d\n",u,s[u].last,s[u].next);
printf("\n");*/
/* for (int u=0;u<=n+1;u++)
printf("%d:%d %d %d\n",u,g[u].a,g[u].b,g[u].ans);*/
}
return 0;
}
D2T1 BOARD
这题的话不难想到对节点标号
常用的技巧就是如果父亲是i,那么儿子就是2*i和2*i+1
你就可以得到这两个点的编号
先让深的一个跳到同一层是肯定的,这个应该知道吧。。
然后我们就考虑跳到了同一层的情况
不难发现,这种走法肯定是最优的
到这里和标解思路是一样的
下面是我yy的做法(正确性未知)
考虑到n很大,这些都没有关系,我们可以写高精度嘛。。
然后我们发现,你走上i层再走下来,代价是2*i
但是你可以节省2^i次方步。。
然后你就可以贪心地走,只要往上走优就往上走
然后就xjb算一下。。
但是考虑到高精度常数巨大,这个方法是实现难度也高。。
于是搞到一般我就放弃了
下面是官方的做法
在我放弃时候,我发现官方的代码贼短,我写几个高精度就快长过他了。。
那么当然是改行啦
题解是这么做的:
一个节点的表示方法大搞有一点点不一样
你用一个长度为n的数组表示
a[i]表示你从第i-1行走到第i行,然后往右走a[i]步
要注意的时候,你这个数组是要进位的,就是说要是你有一层的东西大于了2,那么就相当于上面走了1,然后注意了进位以后,其实就每一个数最大就是1
这样就可以很好地维护处什么向右走再向左走这种情况了
实现很简单,具体看代码。。
然后不难知道,他最后的深度是不会超过n的
然后我们可以暴力枚举他们要在那一层相遇
这个层数我们可以从上往下扫下来
然后我们可以知道他们在之前距离了多少
因为你要是在父亲距离了i,去到儿子就会变成2*i
然后你就看看在这一层的话,相遇的代价是多少
然后我们看下最优值就可以了,由于每一行最大走一步,所以你只需要枚举在那一层相遇就可以
当然如果我们现在的距离太大的话,我们就可以停止了
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int N=100005;
char s[2][N];//两条路径
int a[2][N];//处理完后的路径
int len[2];//处理完后的路径长度
void pushup (int x,int y)
{
a[x][y-1]=a[x][y-1]+a[x][y]/2-(a[x][y]%2==-1);
a[x][y]=abs(a[x][y])%2;
}
void solve (int x)
{
int n=strlen(s[x]);
a[x][0]=1;int now=0;
for (int u=0;u<n;u++)
{
if (s[x][u]=='1') a[x][++now]=0;
if (s[x][u]=='2') a[x][++now]=1;
if (s[x][u]=='L') a[x][now]--;
if (s[x][u]=='R') a[x][now]++;
if (s[x][u]=='U') {pushup(x,now);now--;}
}
len[x]=now;
for (int u=now;u>=1;u--) pushup(x,u);
}
int main()
{
scanf("%s%s",s[0],s[1]);
solve(0);solve(1);
int lalal=min(len[0],len[1]);
/*printf("%d %d %d\n",len[0],len[1],lalal);
for (int u=0;u<=len[0];u++) printf("%d ",a[0][u]);
printf("\n");
for (int u=0;u<=len[1];u++) printf("%d ",a[1][u]);*/
int ans=(1<<20);
int now=0;
for (int u=0;u<=lalal&&now>-(1<<20)&&now<(1<<20);u++)
{
now=now*2+a[0][u]-a[1][u];
ans=min(ans,abs(now)+2*(lalal-u));
}
printf("%d\n",ans+abs(len[0]-len[1]));
return 0;
}
[CEOI2013]D1T3 SPLOT
这题的话,思路大部分是看题解的。。
然后似乎实现方式有一万个不一样。。但是反正我A了。。
讲道理,我完全看不懂标称在写smg
解法
不难想到处理这个可以维护一个站,当出现一个#的时候,就一直pop,直到出现一个S或P为止,然后我们就处理这个信息,把它变成一个新的停车场丢回栈里面
然后我们对每一个G维护5个值,front,back,both,lalal,none
分别表示这个
G里面的车都存在一条路径自由地到S
G里面的车都存在一条路径自由地到T
G里面的车都存在一条路径自由地到S或T
G里面的车都存在一条路径自由地到S或T,并且存在一条路径,使得S和T连通
G里面一辆车都没有
最多可以存在多少台车
不难发现
lalal<front,back<both
然后你就对于每个操作,相当于合并
然后你就大力地分类讨论一下就好了。。
也不是很多,我就写了
20+
条式子,我相信各位看官自己也可以解决,我这里就不再赘述了
然而我并不会这么做,因为我是一个负责的人
那么我就说一下front怎么求,剩下的自己想把。。要不这个页面写不下了
先考虑串联的情况:
由于它是X–Y连起来,所以要是你想考虑Y里面的点,你X必须要留一条路给他
于是第一种可能取值就是
a[x].lalal+a[y].front
要是你不留路的话,那么就是
a[x].front+a[y].none
取max
然后我们考虑并联的情况
第一种情况就是S和T都是空的
第一种取值就是x和y的front
然后当然,我们还有x的both也是有可能有解的,就是通过T,再走Y走回去
那么答案就是
x的both和y的lalal
反过来也一样
第二种情况就是S有东西,T是空的
这个比较简单,就是x的none和y的none+1
第三种就是S空的,T是有的
那么就要留下一条路给T
那么就是一个front,一个lalal加上t的1
没有第四种了
然后就是这样,你就认真地推一下式子,调一下代码就可以了。。
至于输出方案,你可以倒回去,看看答案状态是怎么得出来的,然后在一步一步走回去,注意,当用到一个独立点的时候,他贡献的的是front, back或者both才是合法的,我这里调了一个多小时QAQ
实在不行的可以扒我代码:
#include<cstdio>
#include<bitset>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=100005;
const int NN=N*0.42;
const int MAX=(1<<28);
char ss[N];
int len;
struct qy
{
int s,t;//如果是O或者X,则保存它节点的编号
int k;//它对应的是哪一个空间
int front,back,both,lalal,none;
int a,b,c,d;//它是由什么点决策过来的
qy()
{
front=back=both=lalal=none=-MAX;
a=b=c=d=-1;
}
//都在前面出去 都在后面出去 两边都可以出去 两边都可以出去且存在一条路使得ST相连 空集
//否则就保存它是什么类型 -1:P -2:S
}a[N*2];
bool ooo[N];//这个点是不是必要点
int shen;
stack<int> S;
int g[10],lalal=0;//临时保存一下
bitset<NN> o[NN];
void series ()//串联
{
shen++;
int x=g[2],y=g[1];
a[shen].a=x;a[shen].b=y;
a[shen].s=a[x].s; a[shen].t=a[y].t;
a[shen].front=max(a[x].lalal+a[y].front,a[x].front+a[y].none);
a[shen].back=max(a[x].back+a[y].lalal,a[x].none+a[y].back);
a[shen].both=a[x].front+a[y].back;
a[shen].both=max(a[shen].both,a[x].both+a[y].lalal);
a[shen].both=max(a[shen].both,a[x].lalal+a[y].both);
a[shen].lalal=a[x].lalal+a[y].lalal;
a[shen].none=a[x].none+a[y].none;
S.push(shen);
}
void parallel ()
{
shen++;
int s=g[4],t=g[1];
int x=g[3],y=g[2];
a[shen].a=s;a[shen].b=t;a[shen].c=x;a[shen].d=y;
a[shen].s=a[s].s;a[shen].t=a[t].t;
if (a[s].none==0&&a[t].none==0)//S空T空
{
a[shen].front=max(a[shen].front,a[x].front+a[y].front);
a[shen].front=max(a[shen].front,a[x].both+a[y].lalal);
a[shen].front=max(a[shen].front,a[y].both+a[x].lalal);
a[shen].back=max(a[shen].back,a[x].back+a[y].back);
a[shen].back=max(a[shen].back,a[x].both+a[y].lalal);
a[shen].back=max(a[shen].back,a[x].lalal+a[y].both);
a[shen].both=max(a[shen].both,a[x].both+a[y].both);
a[shen].lalal=max(a[shen].lalal,a[x].both+a[y].lalal);
a[shen].lalal=max(a[shen].lalal,a[y].both+a[x].lalal);
a[shen].none=max(a[shen].none,a[x].none+a[y].none);
}
if (a[s].none==0)//s空t有
{
// printf("OZY2");
a[shen].front=max(a[shen].front,a[x].front+a[y].lalal+1);
a[shen].front=max(a[shen].front,a[y].front+a[x].lalal+1);
a[shen].back=max(a[shen].back,1+a[x].none+a[y].none);
a[shen].both=max(a[shen].both,1+a[x].front+a[y].front);
}
if (a[t].none==0)//s有,t空
{
a[shen].front=max(a[shen].front,a[x].none+a[y].none+1);
a[shen].back=max(a[shen].back,a[x].lalal+a[y].back+1);
a[shen].back=max(a[shen].back,a[y].lalal+a[x].back+1);
a[shen].both=max(a[shen].both,1+a[x].back+a[y].back);
}
a[shen].both=max(a[shen].both,2+a[x].none+a[y].none);
S.push(shen);
}
void solve1 ()//把图构建出来
{
for (int u=1;u<=len;u++)
{
if (ss[u]=='|') continue;
if (ss[u]=='#')//它是一个#号,也就是是一个终结符
{
lalal=0;
while (!S.empty())
{
int x=S.top();
if (a[x].s<0)//它是一个P
break;
g[++lalal]=x;
S.pop();
}
int x=S.top();S.pop();
if (a[x].s==-1)//P类型
parallel();
else series();
/*for (int u=1;u<=shen;u++)
{
if (a[u].s<0) continue;
printf("%d %d %d %d %d %d\n",u,a[u].front,a[u].back,a[u].both,a[u].lalal,a[u].none);
}
system("pause");*/
}
else S.push(u);
}
printf("%d\n",a[shen].front);
/*for (int u=1;u<=num;u++)
printf("%d %d\n",e[u].x,e[u].y);
system("pause");*/
}
void dfs2 (int xx,int yy)//x,y是由什么得出来的
{
/*printf("%d %d\n",xx,yy);
printf("%d %d %d %d\n",a[xx].a,a[xx].b,a[xx].c,a[xx].d);
system("pause");*/
if (xx<=len)
{
if (yy<=3) ooo[a[xx].s]=true;
return ;
}
int shen=xx;
if (a[xx].c==-1)
{
int x=a[xx].a,y=a[xx].b;
if (yy==1)
{
if (a[shen].front==a[x].lalal+a[y].front) {dfs2(x,4);dfs2(y,1);return ;}
if (a[shen].front==a[x].front+a[y].none) {dfs2(x,1);return ;}
}
if (yy==2)
{
if (a[shen].back==a[x].back+a[y].lalal) {dfs2(x,2);dfs2(y,4);return ;}
if (a[shen].back==a[y].back) {dfs2(y,2);return ;}
}
if (yy==3)
{
if (a[shen].both==a[x].front+a[y].back) {dfs2(x,1);dfs2(y,2);return ;}
if (a[shen].both==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
if (a[shen].both==a[x].lalal+a[y].both) {dfs2(x,4);dfs2(y,3);return ;}
}
if (yy==4)
{
if (a[shen].lalal==a[x].lalal+a[y].lalal) {dfs2(x,4);dfs2(y,4);return ;}
}
}
else
{
int s=a[xx].a,t=a[xx].b,x=a[xx].c,y=a[xx].d;
if (a[s].none==0&&a[t].none==0)//S空T空
{
if (yy==1)
{
if (a[shen].front==a[x].front+a[y].front) {dfs2(x,1);dfs2(y,1);return ;}
if (a[shen].front==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
if (a[shen].front==a[y].both+a[x].lalal) {dfs2(x,4);dfs2(y,3);return ;}
}
if (yy==2)
{
if (a[shen].back==a[x].back+a[y].back) {dfs2(x,2);dfs2(y,2);return ;}
if (a[shen].back==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
if (a[shen].back==a[x].lalal+a[y].both) {dfs2(x,4);dfs2(y,3);return ;}
}
if (yy==3)
{
if (a[shen].both==a[x].both+a[y].both) {dfs2(x,3);dfs2(y,3);return ;}
}
if (yy==4)
{
if (a[shen].lalal==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
if (a[shen].lalal==a[y].both+a[x].lalal) {dfs2(y,3);dfs2(x,4);return ;}
}
}
if (a[s].none==0)//s空t有
{
if (yy==1)
{
if (a[shen].front==a[x].front+a[y].lalal+1) {ooo[a[t].s]=true;dfs2(x,1);dfs2(y,4);return ;}
if (a[shen].front==a[y].front+a[x].lalal+1) {ooo[a[t].s]=true;dfs2(x,4);dfs2(y,1);return ;}
}
if (yy==2)
{
if (a[shen].back==1+a[x].none+a[y].none) {ooo[a[t].s]=true;return ;}
}
if (yy==3)
{
if (a[shen].both==1+a[x].front+a[y].front) {ooo[a[t].s]=true;dfs2(x,1);dfs2(y,1);return ;}
}
}
if (a[t].none==0)//s有,t空
{
if (yy==1)
{
if (a[shen].front==a[x].none+a[y].none+1) {ooo[a[s].s]=true;return ;}
}
if (yy==2)
{
if (a[shen].back==a[x].lalal+a[y].back+1) {ooo[a[s].s]=true;dfs2(x,4);dfs2(y,2);return ;}
if (a[shen].back==a[y].lalal+a[x].back+1) {ooo[a[s].s]=true;dfs2(x,2);dfs2(y,4);return ;}
}
if (yy==3)
{
if (a[shen].both==1+a[x].back+a[y].back) {ooo[a[s].s]=true;dfs2(x,2);dfs2(y,2);return ;}
}
}
if (yy==3)
{
if (a[shen].both==2+a[x].none+a[y].none) {ooo[a[s].s]=true;ooo[a[t].s]=true;return ;}
}
}
return ;
}
int main()
{
scanf("%s",ss+1);len=strlen(ss+1);
for (int u=1;u<=len;u++)
{
if (ss[u]=='o')//这个开始没有车
{
a[u].s=a[u].t=u;
a[u].front=a[u].back=a[u].both=1;
a[u].lalal=a[u].none=0;
}
if (ss[u]=='x')
{
a[u].s=a[u].t=u;
a[u].front=a[u].back=a[u].both=1;
a[u].lalal=a[u].none=-MAX;
}
if (ss[u]=='P') a[u].s=-1;
if (ss[u]=='S') a[u].s=-2;
if (ss[u]=='|'||ss[u]=='#') a[u].s=-3;
}
shen=len;
solve1();
/* for (int u=1;u<=shen;u++)
{
if (a[u].s<0) continue;
printf("%d s:%d t:%d front:%d back:%d both:%d lalal:%d none:%d\n",u,a[u].s,a[u].t,a[u].front,a[u].back,a[u].both,a[u].lalal,a[u].none);
}
system("pause");*/
memset(ooo,false,sizeof(ooo));
dfs2(shen,1);
for (int u=1;u<=len;u++)
{
if (ss[u]=='o')//这个开始没有车
{
if (ooo[a[u].s]) printf("x");
else printf("o");
}
else printf("%c",ss[u]);
}
return 0;
}