P4692 [Ynoi2016] 谁的梦

P4692 [Ynoi2016] 谁的梦(set)

首先正难则反是必须想到的,我们可以考虑先不管所有的值,把全部值都作为答案统计一边,然后减去贡献即可。

重点在于怎么减去贡献,容易发现,我们这样做其实就是把每个序列分成了很多段,于是我们考虑用 set 维护每一个断点的前驱后继,然后暴力算答案即可。

注意有一个坑点是 0 没用逆元,必须特判。

时间复杂度 \(O(nlogn)\)

代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define int long long
const int N=2e5+5,MOD=19260817;
int n,m,len[N],tot2,res,sum1[N],sum2[N],Cnt[N],tot,Sum;
vector<int>p[N];
map<int,int> Map;
map<pair<int,int>,int> Map2;
set<int>st[N*5];
set<int>::iterator it,IT;
int QuickPow(int x,int y,int res=1){for(;y;y>>=1,x=x*x%MOD)if(y&1)res=res*x%MOD;return res;}
int Getpos(int x){if(Map.find(x)==Map.end())sum1[Map[x]=++tot]=Sum;return Map[x];}
int GetPos(int x,int y) {
	if(Map2.find(make_pair(x,y))==Map2.end()){
		st[Map2[make_pair(x,y)]=++tot2].insert(0),st[tot2].insert(len[y]+1);
		sum2[tot2]=(len[y]*(len[y]+1)>>1)%MOD;
	}
	return Map2[make_pair(x,y)];
}
void Insert(int c,int x,int now){
	res-=Sum-((!Cnt[c])?sum1[c]:0);
	if(!sum2[x]) Cnt[c]--;
	else sum1[c]=sum1[c]*QuickPow(sum2[x],MOD-2)%MOD;
	it=st[x].lower_bound(now),IT=--it,++it;
	sum2[x]=(sum2[x]-((*it-*IT)*(*it-*IT-1)>>1))%MOD;
	sum2[x]=(sum2[x]+((now-*IT)*(now-*IT-1)>>1))%MOD;
	sum2[x]=(sum2[x]+((*it-now)*(*it-now-1)>>1)+MOD)%MOD;
	if(!sum2[x])++Cnt[c];
	else sum1[c]=sum1[c]*sum2[x]%MOD;
	res+=Sum-((!Cnt[c])?sum1[c]:0),st[x].insert(now);
	return ;
}
void Delete(int c,int x,int now){
	res-=Sum-((!Cnt[c])?sum1[c]:0);
	if(!sum2[x]) Cnt[c]--;
	else sum1[c]=sum1[c]*QuickPow(sum2[x],MOD-2)%MOD;
	st[x].erase(now),it=st[x].lower_bound(now),IT=--it,++it;
	sum2[x]=(sum2[x]-((now-*IT)*(now-*IT-1)>>1))%MOD;
	sum2[x]=(sum2[x]-((*it-now)*(*it-now-1)>>1))%MOD;
	sum2[x]=(sum2[x]+((*it-*IT)*(*it-*IT-1)>>1)+MOD+MOD)%MOD;
	if(!sum2[x]) Cnt[c]++;
	else sum1[c]=sum1[c]*sum2[x]%MOD;
	res+=Sum-((!Cnt[c])?sum1[c]:0);
	return ;
}
signed main() {
	read(n),read(m),Sum=1;
	for(int i=1;i<=n;i++) read(len[i]),Sum=(len[i]*(len[i]+1)>>1)%MOD*Sum%MOD,p[i].resize(len[i]+2);
	for(int i=1;i<=n;i++) for(int j=1;j<=len[i];j++) read(p[i][j]);
	for(int i=1;i<=n;i++) for(int j=1;j<=len[i];j++) Insert(Getpos(p[i][j]),GetPos(p[i][j],i),j);
	res=(res%MOD+MOD)%MOD;
	write(res),putchar('\n');
	for(int i=1,x,y,z;i<=m;i++){
		read(x),read(y),read(z);
		Delete(Getpos(p[x][y]),GetPos(p[x][y],x),y),p[x][y]=z;
		Insert(Getpos(p[x][y]),GetPos(p[x][y],x),y);
		res=(res%MOD+MOD)%MOD;
		write(res),putchar('\n');
	}
	return 0;
}
posted @ 2021-04-16 16:01  __Anchor  阅读(41)  评论(0编辑  收藏  举报