专栏文章

P14192 [ICPC 2024 Hangzhou R] Fuzzy Ranking 题解

P14192题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min2ta46
此快照首次捕获于
2025/12/01 19:38
3 个月前
此快照最后确认于
2025/12/01 19:38
3 个月前
查看原文

思路分析:

考虑排名在前的向排名在后的连边,那么“优越于”即可达,“模糊对”即强联通。设区间内第 ii 个 SCC 的大小分别为 SiS_i,答案为 Si(Si1)2\sum \dfrac{S_i\cdot(S_i-1)}{2}
Kosaraju 或 Tarjan 跑一边求出每个点所在的 SCC,发现这个问题变成了经典的莫队板题,但强制在线。可以分块大力维护,但直觉上都图论建模了大概率是有性质的。输出每个点 SCC 的编号发现每个 SCC 都是连续的一段,可以多随几组数据看看。
证明:每次建边都是相邻点,即合并相邻的 SCC,一开始都是独立的,不难归纳出这个结论。
于是分成 SCC 整体和区间左右的散块分别做即可,前缀和维护,注意开 long long

AC Code:

CPP
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int t[N],c[N];
bitset<N>vis;
vector<int>a[N],e[N],l[N],r[N];
vector<long long>s[N];
void dfs(int u,int col){
	vis[u]=1,c[u]=col;
	for(int v:e[u])if(!vis[v])dfs(v,col);
}
void solve(){
	int n,k,q;cin>>n>>k>>q;
	for(int i=1;i<=n;i++)e[i].clear();
	for(int i=1;i<=k;i++){
		a[i].resize(n+2);
		for(int j=1;j<=n;j++)cin>>a[i][j];
		for(int j=1;j<n;j++)e[a[i][j+1]].push_back(a[i][j]);
	}
	vis.reset();
	for(int j=1;j<=n;j++)if(!vis[a[1][j]])dfs(a[1][j],j);
	for(int i=1;i<=k;i++){
		l[i].resize(n+2),r[i].resize(n+2),s[i].resize(n+2);
		int L=l[i][1]=1,R=r[i][n]=n;
		for(int j=1;j<=n;j++)
			s[i][j]=0;
		for(int j=2;j<=n;j++){
			if(c[a[i][j]]!=c[a[i][j-1]])
				s[i][j-1]+=1ll*(j-L)*(j-L-1)/2,L=j;
			l[i][j]=L,s[i][j]+=s[i][j-1];
		}
		for(int j=n-1;j;j--){
			if(c[a[i][j]]!=c[a[i][j+1]])R=j;
			r[i][j]=R;
		}
	}
	long long ans=0;
	while(q--){
		int id,L,R;cin>>id>>L>>R;id=(id+ans)%k+1;
		L=(L+ans)%n+1;R=(R+ans)%n+1;if(L>R)swap(L,R);
		if(c[a[id][L]]==c[a[id][R]])ans=1ll*(R-L+1)*(R-L)/2;
		else ans=s[id][l[id][R]-1]-s[id][r[id][L]]+
				1ll*(r[id][L]-L+1)*(r[id][L]-L)/2+
				1ll*(R-l[id][R]+1)*(R-l[id][R])/2;
		cout<<ans<<'\n';
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;while(T--)solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...