题目戳这里
我们只需要计算每增加一条线后穿过了几条已有的线即可。为了方便,我们令(K le N/2),并且给每条线一个方向,即(x)到((x+K) ; mod ; N)。然后我们假设现在我们正在链接(a)到((a+K) ; mod ; N)这条线,于是他穿过的线就是从((a-K,a+k))(模(K)意义下)$这段区间中点射出边的数目,拿个树状数组维护一下即可。
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long ll;
#define lowbit(a) (a&-a)
const int maxn = 1000010;
int N,K,now,tree[maxn]; ll ans = 1LL;
inline void ins(int a) { for (++a;a <= N;a += lowbit(a)) ++tree[a]; }
inline ll calc(int a) { int ret = 0; for (++a;a;a -= lowbit(a)) ret += tree[a]; return (ll)ret; }
int main()
{
freopen("755D.in","r",stdin);
freopen("755D.out","w",stdout);
scanf("%d %d",&N,&K); if (N - K < K) K = N-K;
do
{
if (now+K-1<N)
{
ans += calc(now+K-1)-calc(now);
if (now - K < 0) ans += calc(now-1)+calc(N-1)-calc(now-K+N);
else ans += calc(now-1)-calc(now-K);
}
else
{
ans += calc(N-1)-calc(now)+calc(now+K-1-N);
if (now - K < 0) ans += calc(now-1)+calc(N-1)-calc(now-K+N);
else ans += calc(now-1)-calc(now-K);
}
ins(now); now += K; if (now >= N) now -= N;
printf("%lld ",++ans);
}
while (now);
fclose(stdin); fclose(stdout);
return 0;
}