Solution 1
N<=100 K<=200
暴力模拟,记录每个点走过的位置
复杂度
O
(
N
M
)
O(NM)
O(NM)
Solution 2
M=1e18
我们知道总共最多经过N个点,所以M可以看成无限走
如果把每
K
K
K轮交换称作一次置换,从每个点,向一次置换后它的位置连一条边,则会发现形成的这个图是由若干环组成的,也有一些是自环,环上的边可以看成一次置换,也就是说每条边上实际是由
K
K
K次小交换组成的
比如样例的图是这样的
盗一下大佬的图
经过
K
K
K轮之后,1号奶牛就到了5号位置
因为M是无限大,所以最终环上的点是可以互相到达的,也就是它们的答案是相等的
如果用
S
i
S_i
Si表示
i
i
i这个点经过一次置换能到达的点的集合,则一个环的答案就是环上所有点
S
S
S集合的并集,因为一次置换最多有
2
∗
K
2*K
2∗K次换位,所以
∑
S
i
≤
2
∗
K
\sum S_i\leq 2*K
∑Si≤2∗K,可以对每个点开vector存起来,统计并集就用一个桶即可
Solution 3
有了
M
M
M的限制后,从每个点出发不一定能遍历到环上所有点,所以每个点的答案可能不同,我们对环分两类讨论
设在
M
M
M次内,能进行的置换的个数为
T
T
T,余下不足一次置换的个数为
R
R
R
也就是
T
=
M
/
K
,
R
=
M
−
K
∗
T
T=M/K,R=M-K*T
T=M/K,R=M−K∗T
1:环的大小小于等于T
此时环依然能遍历完,处理和上面是一样的
2:环的大小大于T
也就是说从每个点出发不能遍历环上的所有点,如图
举个例子,从一号点出发,绿色的线就是T次置换经过的点,蓝色的线就是剩下的不足一次置换的R次交换经过的点,那么1号点的答案就是被覆盖部分的并集,形式化地说
设点
i
i
i经过
T
T
T次置换到达的点为
j
j
j
答案就是
S
i
∪
S
i
+
1
∪
…
…
S
j
∪
L
j
S_i \cup S_{i+1} \cup ……S_j \cup L_j
Si∪Si+1∪……Sj∪Lj
其中
L
i
L_i
Li表示从
i
i
i号点出发进行
R
R
R次交换能到达的点的集合
这个式子可以用一个桶处理
但是暴力这样统计答案是
O
(
N
K
)
O(NK)
O(NK)的,依然会T,而我们浪费的地方就是没有利用已经统计过的信息
考虑到从每个点出发的距离都相等,所以可以看成是若干长度相等的区间
这就是经典的滑动窗口问题,可以
O
(
n
)
O(n)
O(n)做,设
l
,
r
l,r
l,r表示当前区间,当
r
r
r加一的时候,
l
l
l也跟着加一,同时删掉
l
l
l的贡献,加上
r
r
r的贡献,因为是环所以破环成链倍长即可
如果不懂看下边的图
当
l
l
l从1转移到5时,删掉
1
1
1 ~
5
5
5之间的绿色边,删掉
4
4
4开始的蓝色边,加上
4
4
4 ~
3
3
3的绿色边,最后加上从
3
3
3开始的蓝色边
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5+7;
struct Swap
{
int x,y;
}seq[N];
vector<int> res[N],pos[N];
int a[N];
int Next[N];
int n;
LL k,m,R,T;
bool vis[N];
vector<int> cir[N];
int siz[N];
int cnt=0;
void Find(int x)
{
int y=x;
++cnt;
do
{
vis[y]=1;
cir[cnt].push_back(y);
y=Next[y];
}while(x!=y);
siz[cnt]=cir[cnt].size();
}
int Ans[N];
int t[N];
int ans=0;
void add(int x,int opt)
{
if(opt==1)
{
for(int i=0;i<pos[x].size();i++)
{
int y=pos[x][i];
if(t[y]==0) ans++;
t[y]++;
}
}
if(opt==2)
{
for(int i=0;i<res[x].size();i++)
{
int y=res[x][i];
if(t[y]==0) ans++;
t[y]++;
}
}
}
void del(int x,int opt)
{
if(opt==1)
{
for(int i=0;i<pos[x].size();i++)
{
int y=pos[x][i];
if(t[y]==1) ans--;
t[y]--;
}
}
if(opt==2)
{
for(int i=0;i<res[x].size();i++)
{
int y=res[x][i];
if(t[y]==1) ans--;
t[y]--;
}
}
}
void calc(int id)
{
if(siz[id]<=T)
{
for(int i=0;i<siz[id];i++)
{
int x=cir[id][i];
add(x,1);
}
for(int i=0;i<siz[id];i++)
{
int x=cir[id][i];
Ans[x]=ans;
}
for(int i=0;i<siz[id];i++)
{
int x=cir[id][i];
del(x,1);
}
return;
}
else
{
for(int i=0;i<siz[id];i++)
{
int x=cir[id][i];
cir[id].push_back(x);
}
int l=0,r=T-1;
for(int i=l;i<=r;i++)
{
int x=cir[id][i];
add(x,1);
}
add(cir[id][T],2);
Ans[cir[id][l]]=ans;
while(l<siz[id]-1)
{
if(l<=r) del(cir[id][l],1);
del(cir[id][r+1],2);
l++;r++;
if(l<=r) add(cir[id][r],1);
add(cir[id][r+1],2);
Ans[cir[id][l]]=ans;
}
for(int i=l;i<=r;i++)
del(cir[id][i],1);
del(cir[id][r+1],2);
}
}
void init()
{
for(int i=1;i<=k;i++)
{
int x=seq[i].x,y=seq[i].y;
pos[a[x]].push_back(y);
pos[a[y]].push_back(x);
if(i<=R)
{
res[a[x]].push_back(y);
res[a[y]].push_back(x);
}
swap(a[x],a[y]);
}
for(int i=1;i<=n;i++) Next[a[i]]=i;
for(int i=1;i<=n;i++)
if(!vis[i])
{
Find(i);
calc(cnt);
}
}
int main()
{
scanf("%d %lld %lld",&n,&k,&m);
T=m/k;
R=m-k*T;
for(int i=1;i<=k;i++)
scanf("%d %d",&seq[i].x,&seq[i].y);
for(int i=1;i<=n;i++)
{
pos[i].push_back(i);
res[i].push_back(i);
a[i]=i;
}
init();
for(int i=1;i<=n;i++)
printf("%d\n",Ans[i]);
return 0;
}