关于珂朵莉树

前言

几个月前学长就讲过珂朵莉树,当时对指针和STL有股莫名的畏惧,咕到现在才入门

定义

\(STL\)容器维护颜色均摊段
可以理解为不定长度的分块-但一定要有区间推平操作+随机数据
总体来说,是不稳定的优雅的暴力

思想

举个例子image这个序列
如何维护每种值所代表的信息?
一种很自然的想法是把相同的值全部放到一起
image
然后维护左右端点,进行直接查询,推出结构体储存

struct Node{
	int lz,rz;mutable int val;
	Node(int lz,int rz=0,int val=0):lz(lz),rz(rz),val(val){};
	inline bool operator<(const Node &x)const{
		return lz<x.lz;
	}
};
  • lz: 左边界下标
  • rz: 右边界下标
  • val: 当前区间的值
  • Node(): 初始化,只需要左值
  • 重载<运算符,按照左端点排序

然后就是最重要的\(split\)(分割)函数了

inline auto split(int pos){
	auto it=s.lower_bound(Node(pos));
	if(it!=s.end()&&it->lz==pos) return it;
	it--;
	if(it->rz<pos) return s.end();
	int l=it->lz,r=it->rz,w=it->val;
	s.rease(it);
	s.insert(Node(l,pos-1,w));
	return s.insert(Node(pos,r,w)).first;
}

先解释一下,这个\(auto\)的全写是

set<Node>::iterator

也就是set的迭代器的意思
逐行解释一下
首先,对于每次推平操作,会有一些Node被合并,也会有一些Node被拆开,\(split\)就是找一个位置pos,把pos对应的Node分割成\([l,pos-1]\)\([pos,r]\)两个区间,如果pos直接是一个区间的开头或结尾,直接返回区间即可

inline auto split(int pos){// 
	auto it=s.lower_bound(Node(pos));//查询pos所在区间 
	if(it!=s.end()&&it->lz==pos) return it;// pos是该区间开头时 
	it--;//将it往前挪 
	if(it->rz<pos) return s.end();// pos太大,直接返回s的最后 
	int l=it->lz,r=it->rz,w=it->val;
	s.erase(it);//原来的区间直接删掉 
	s.insert(Node(l,pos-1,w));//分割成两个小区间 
	return s.insert(Node(pos,r,w)).first;
}

然后就是合并操作,我喜欢把函数命名为\(gto(get-together)\)

inline void gto(int l,int r,int w){//将区间l~r变成整块值为w的块
	auto itr=split(r+1),itl=split(l);//找到左右端点
	s.erase(itl,itr);//删除原区间
	s.insert(Node(l,r,w));//加入新区间
}

为什么先获取 \(itr\) 再获取 \(itl\) ?
因为如果先分割左边的l,右边的r可能会错位,而先后面再前面就不会错位
基本操作就是这两种,然后就是愉快的暴力拉

例题

1.CF896C Willem, Chtholly and Seniorious

珂朵莉树的起源,就不详细啰嗦了,哪里的题解比我讲得好的多,放个代码叭

/*
雲璃猫猫が好きです
すべての生命よ,歌のように輝いています
截剣式、斬、断、破です!
*/
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int long long
#define INF 1e18
#define lb long double
#define ls (id<<1)
#define rs (id<<1|1)
#define rep(i,l,r,k) for(int i=(l);i<=(r);i+=(k))
#define dep(i,r,l,k) for(int i=(r);i>=(l);i-=(k))
#define tep(x,y) for(auto x:y)
#define wl while
#define mk(a,b) make_pair(a,b)
#define me(a,b) memset(a,b,sizeof(a))
#define pb(x) push_back(x)
#define pr putchar
#define fi first
#define se second
#define max(a,b)((a)>(b)?(a):(b))
#define min(a,b)((a)<(b)?(a):(b))
using namespace std;
random_device rd;
unsigned int seed=rd();
mt19937 Rand(seed);
typedef pair<int,int> pii;
const int M=2e5+110,mod=1e9+7,Mod=998244353;
__gnu_pbds::gp_hash_table<string,int>ml;
inline int read(){int sum=0,k=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')k=-1;c=getchar();
	}while(c>='0'&&c<='9'){sum=sum*10+c-48;c=getchar();
	}return sum*k;
}inline void wr(int x){if(x<0) putchar('-'),x=-x;
	if(x>9) wr(x/10);return void(putchar(x%10+'0'));}
int sed,n,m,vmax;
inline int rnd(){
	int res=sed;
	sed=(sed*7+13)%1000000007;
	return res;
}
struct Node{
	int lz,rz;mutable int val;
	Node(int lz,int rz=0,int val=0):lz(lz),rz(rz),val(val){};
	inline bool operator<(const Node &x)const{
		return lz<x.lz;
	}
};set<Node>s;
inline auto split(int pos){
	auto it=s.lower_bound(Node(pos));
	if(it!=s.end()&&it->lz==pos) return it;
	it--;
	if(it->rz<pos) return s.end();
	int l=it->lz,r=it->rz,w=it->val;
	s.erase(it);
	s.insert(Node(l,pos-1,w));
	return s.insert(Node(pos,r,w)).fi;
}
inline void opt1(int l,int r,int w){
	auto itr=split(r+1),itl=split(l);
	auto it=itl;
	for(;it!=itr;it++) 
		it->val+=w;
}
inline void opt2(int l,int r,int w){
	auto itr=split(r+1),itl=split(l);
	s.erase(itl,itr);
	s.insert(Node(l,r,w));
}
inline void opt3(int l,int r,int x){
	auto itr=split(r+1),itl=split(l);
	priority_queue<pii,vector<pii>,greater<pii>>q;
	for(auto it=itl;it!=itr;it++){
		q.push(mk(it->val,(it->rz-it->lz+1)));
	}
	while(!q.empty()){
		int val=q.top().fi,num=q.top().se;
		q.pop();
		if(num>=x) return cout<<val<<'\n',void();
		else x-=num;
	}
}
inline int qp(int x,int y,int p,int res=1){
	x%=p;
	while(y){
		if(y&1) res=1LL*res*x%p;
		x=1LL*x*x%p;
		y>>=1;
	}
	return res;
}

inline void opt4(int l,int r,int x,int y){
	auto itr=split(r+1),itl=split(l);int ans=0;
	for(auto it=itl;it!=itr;it++){
		int va=qp(it->val,x,y);
		ans=(ans+va*(it->rz-it->lz+1)%y)%y;
	}
	cout<<ans<<'\n';
}
int a[M];
signed main(){
	n=read(),m=read(),sed=read(),vmax=read();
	rep(i,1,n,1){
		a[i]=(rnd()%vmax)+1;
		s.insert(Node(i,i,a[i]));
	}
	rep(i,1,m,1){
		int op=(rnd()%4)+1,l=(rnd()%n)+1,r=(rnd()%n)+1,x,y;
		if(l>r) swap(l,r);
		if(op==3) x=(rnd()%(r-l+1))+1;
		else x=(rnd()%vmax)+1;
		if(op==4) y=(rnd()%vmax)+1;
//		cout<<"op:"<<op<<" l:"<<l<<" r:"<<r<<" x:"<<x<<" y:"<<y<<'\n';
		if(op==1) opt1(l,r,x);
		if(op==2) opt2(l,r,x);
		if(op==3) opt3(l,r,x);
		if(op==4) opt4(l,r,x,y);
	}
	return 0;
}
/*
begin:09:01
end::09:28
*/

2.P4315 月下“毛景树”

看到区间推平,珂朵莉!

#include<bits/stdc++.h>
#define int long long
#define ddq set<Node>::iterator
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
using namespace std;
const int M=2e5+110;

inline int read(){
    int sum=0,k=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9'){sum=sum*10+c-48;c=getchar();}
    return sum*k;
}

struct Node{
    int lz,rz;mutable int val;
    Node(int lz,int rz=0,int val=0):lz(lz),rz(rz),val(val){};
    inline bool operator<(const Node &a)const{
        return lz<a.lz;
    }
};set<Node>s;

inline ddq split(int pos){
	ddq it=s.lower_bound(Node(pos));
	if(it->lz==pos&&it!=s.end()) return it;
	it--;
	if(it->rz<pos) return s.end();
	int l=it->lz,r=it->rz,w=it->val;
	s.erase(it);
	s.insert(Node(l,pos-1,w));
	return s.insert(Node(pos,r,w)).fi;
}

inline void gto(int l,int r,int val){
    if(l>r) return;
    ddq itr=split(r+1),itl=split(l);
    s.erase(itl,itr);
    s.insert(Node(l,r,val));
}

inline void ad(int l,int r,int val){//暴力遍历之间的每一个区间加值
    if(l>r) return;
    ddq itr=split(r+1),itl=split(l);
    for(ddq it=itl;it!=itr;it++)
        it->val+=val;
}

inline int ask(int l,int r){//暴力查找
    if(l>r) return -1e18;
    int maxx=-1e18;
    ddq itr=split(r+1),itl=split(l);
    for(ddq it=itl;it!=itr;it++)
        maxx=max(maxx,it->val);
    return maxx;
}

vector<pair<int,int>> Ed[M];
int a[M],Deep[M],Fa[M],Son[M],Siz[M],Id[M],Top[M],Ti=0;
pair<int,int> edge[M]; // 存储每条边的两个端点

inline void Adde(int u,int v,int w){
    Ed[u].push_back(mk(v,w));
    Ed[v].push_back(mk(u,w));
}

inline void dfs1(int u,int f){
    Fa[u]=f;Deep[u]=Deep[f]+1;
    Siz[u]=1;
    for(auto i:Ed[u]){
        int v=i.fi,w=i.se;
        if(v==f) continue;
        a[v]=w; // 边权存在子节点上
        dfs1(v,u);
        Siz[u]+=Siz[v];
        if(Siz[Son[u]]<Siz[v])
            Son[u]=v;
    }
}

inline void dfs2(int u,int topf){
    Id[u]=++Ti;Top[u]=topf;
    if(!Son[u]) return;
    dfs2(Son[u],topf);
    for(auto i:Ed[u]){
        int v=i.fi;
        if(v==Fa[u]||v==Son[u]) continue;
        dfs2(v,v);
    }
}

inline void ch(int k,int w){//第k条树枝 
    int u=edge[k].fi,v=edge[k].se;
    if(Deep[u]<Deep[v]) swap(u,v);
    gto(Id[u],Id[u],w);
}

inline void co(int u,int v,int w){
    while(Top[u]!=Top[v]){
        if(Deep[Top[u]]<Deep[Top[v]]) swap(u,v);
        gto(Id[Top[u]],Id[u],w);
        u=Fa[Top[u]];
    }
    if(Deep[u]>Deep[v]) swap(u,v);
    if(u!=v) gto(Id[u]+1,Id[v],w);
}

inline void Add(int u,int v,int w){
    while(Top[u]!=Top[v]){
        if(Deep[Top[u]]<Deep[Top[v]]) swap(u,v);
        ad(Id[Top[u]],Id[u],w);
        u=Fa[Top[u]];
    }
    if(Deep[u]>Deep[v]) swap(u,v);
    if(u!=v) ad(Id[u]+1,Id[v],w);
}

inline int Max(int u,int v){
    int maxx=-1e18;
    while(Top[u]!=Top[v]){
        if(Deep[Top[u]]<Deep[Top[v]]) swap(u,v);
        maxx=max(maxx,ask(Id[Top[u]],Id[u]));
        u=Fa[Top[u]];
    }
    if(Deep[u]>Deep[v]) swap(u,v);
    if(u!=v) maxx=max(maxx,ask(Id[u]+1,Id[v]));
    return maxx;
}
signed main(){
    int n=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read(),w=read();
        edge[i]=mk(u,v); // 存储边的两个端点
        Adde(u,v,w);
    }
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=n;i++) s.insert(Node(Id[i],Id[i],a[i]));//新序列的珂朵莉树,对Id[i]建
    while(1){
        string cs;cin>>cs;
        if(cs=="Stop") break;
        if(cs=="Change"){
            int k=read(),w=read();
            ch(k,w);
        }
        else if(cs=="Cover"){
            int u=read(),v=read(),w=read();
            co(u,v,w);
        }
        else if(cs=="Add"){
            int u=read(),v=read(),w=read();
            Add(u,v,w);
        }
        else if(cs=="Max"){
            int u=read(),v=read();
            printf("%lld\n",Max(u,v));
        }
    }
    return 0;
}
  1. P5350 序列
    想一想暴力取出的魅力
#include<bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f
#define ddq set<Node>::iterator
using namespace std;
const int M=2e5+110,Mod=1e9+7;
inline int read(){int sum=0,k=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')k=-1;c=getchar();
	}while(c>='0'&&c<='9'){sum=sum*10+c-48;c=getchar();
	}return sum*k;
}inline void wr(int x){if(x<0) putchar('-'),x=-x;
	if(x>9) wr(x/10);return void(putchar(x%10+'0'));
}
struct Node{
	int lz,rz;mutable int val;
	Node(int lz,int rz=0,int val=0):lz(lz),rz(rz),val(val){};
	inline bool operator<(const Node &a)const{
		return lz<a.lz;
	}
};set<Node>s;
inline ddq split(int pos){
	ddq it=s.lower_bound(Node(pos));
	if(it!=s.end()&&it->lz==pos) return it;
	it--;
	if(it->rz<pos) return s.end();
	int l=it->lz,r=it->rz,val=it->val;
	s.erase(it);
	s.insert(Node(l,pos-1,val));
	return s.insert(Node(pos,r,val)).first;
}
inline void gto(int l,int r,int val){
	ddq itr=split(r+1),itl=split(l);
	s.erase(itl,itr);
	s.insert(Node(l,r,val%Mod));
}
inline void ad(int l,int r,int val){
	ddq itr=split(r+1),itl=split(l);
	for(ddq it=itl;it!=itr;it++)
		it->val+=val,it->val%=Mod;
}
inline void ask(int l,int r){
	ddq itr=split(r+1),itl=split(l);int res=0;
	for(ddq it=itl;it!=itr;it++)
		res+=(((it->rz)-(it->lz)+1)*(it->val));
	wr(res%Mod);putchar('\n');
}
int n,m,tot=0,va[M],ls[M],rs[M];
inline void cop(int l1,int r1,int l2,int r2){
	ddq itr=split(r1+1),itl=split(l1);
	for(ddq it=itl;it!=itr;it++)
		ls[++tot]=l2+it->lz-l1,rs[tot]=l2+it->rz-l1,va[tot]=it->val;
	for(int i=1;i<=tot;++i){
		gto(ls[i],rs[i],va[i]);
	}tot=0;
}
inline void ex(int l1,int r1,int l2,int r2){
	if(l2>l1) swap(l1,l2),swap(r1,r2);
	cop(l1,r1,n+1,n+r1-l1+1);
	cop(l2,r2,l1,r1);
	cop(n+1,n+r1-l1+1,l2,r2);
}
vector<Node>g;
inline void fan(int l,int r){
	ddq itr=split(r+1),itl=split(l);
	int aa=r;g.clear();
	for(ddq it=itl;it!=itr;it++){
		int l=it->lz,r=it->rz,vl=it->val;
		g.push_back(Node(l,r,vl));
	}
	s.erase(itl,itr);
	for(int i=0;i<(int)g.size();i++){
		s.insert(Node(aa-(g[i].rz-g[i].lz),aa,g[i].val));
		aa-=(g[i].rz-g[i].lz+1);
	}
}
inline void la(){
	ddq itr=split(n+1),itl=split(1);
	for(ddq it=itl;it!=itr;it++)
		for(int i=it->lz;i<=it->rz;i++)
			wr(it->val),putchar(' ');
	putchar('\n');
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++) s.insert(Node(i,i,read()));	
	while(m--){
		int opt=read();
		if(opt==1){
			int l=read(),r=read();
			ask(l,r);
		}else if(opt==2){
			int l=read(),r=read(),val=read();
			gto(l,r,val);
		}else if(opt==3){
			int l=read(),r=read(),val=read();
			ad(l,r,val);
		}else if(opt==4){
			int l1=read(),r1=read(),l2=read(),r2=read();
			cop(l1,r1,l2,r2);
		}else if(opt==5){
			int l1=read(),r1=read(),l2=read(),r2=read();
			ex(l1,r1,l2,r2);
		}else if(opt==6){
			int l=read(),r=read();
			fan(l,r);
		}
	}
	la();
	return 0;
}
  1. P5251 [LnOI2019] 第二代图灵机
    线段树,珂朵莉一起维护
/*
雲璃猫猫が好きです
すべての生命よ,歌のように輝いています
截剣式、斬、断、破です!
*/
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define int long long
#define INF 1e18
#define lb long double
#define ls (id<<1)
#define rs (id<<1|1)
#define rep(i,l,r,k) for(int i=(l);i<=(r);i+=(k))
#define dep(i,r,l,k) for(int i=(r);i>=(l);i-=(k))
#define tep(x,y) for(auto x:y)
#define wl while
#define mk(a,b) make_pair(a,b)
#define me(a,b) memset(a,b,sizeof(a))
#define pb(x) push_back(x)
#define pr putchar
#define fi first
#define se second
using namespace std;
random_device rd;
unsigned int seed=rd();
mt19937 Rand(seed);
typedef pair<int,int> pii;
const int M=2e5+110,mod=1e9+7,Mod=998244353;
__gnu_pbds::gp_hash_table<string,int>ml;
inline int read(){int sum=0,k=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')k=-1;c=getchar();
	}while(c>='0'&&c<='9'){sum=sum*10+c-48;c=getchar();
	}return sum*k;
}inline void wr(int x){if(x<0) putchar('-'),x=-x;
	if(x>9) wr(x/10);return void(putchar(x%10+'0'));}
struct Node{
	int lz,rz;mutable int col;
	Node(int lz,int rz=0,int val=0):lz(lz),rz(rz),col(val){};
	inline bool operator <(const Node &x)const{
		return lz<x.lz;
	}
};set<Node>s;
inline auto split(int pos){// 
	auto it=s.lower_bound(Node(pos));//查询pos所在区间 
	if(it!=s.end()&&it->lz==pos) return it;//pos是该区间开头时 
	it--;//将it往前挪 
	if(it->rz<pos) return s.end();//psos太大,直接返回s的最后 
	int l=it->lz,r=it->rz,w=it->col;
	s.erase(it);//原来的区间直接删掉 
	s.insert(Node(l,pos-1,w));//分割成两个小区间 
	return s.insert(Node(pos,r,w)).first;
}
int n,m,c,a[M],b[M],sum[M<<2],mx[M<<2],mi[M<<2];
inline void build(int id,int l,int r){
	if(l==r)
		return sum[id]=mx[id]=mi[id]=a[l],void();
	int Mid=(l+r)>>1;
	build(ls,l,Mid);build(rs,Mid+1,r);
	sum[id]=sum[ls]+sum[rs];
	mx[id]=max(mx[ls],mx[rs]);
	mi[id]=min(mi[ls],mi[rs]);
}
inline int ask_Sum(int id,int l,int r,int L,int R){
	if(l>=L&&r<=R) return sum[id];
	int Mid=(l+r)>>1,res=0;
	if(Mid>=L) res+=ask_Sum(ls,l,Mid,L,R);
	if(Mid<R) res+=ask_Sum(rs,Mid+1,r,L,R);
	return res;
}
inline int ask_Max(int id,int l,int r,int L,int R){
	if(l>=L&&r<=R) return mx[id];
	int Mid=(l+r)>>1,res=-INF;
	if(Mid>=L) res=max(res,ask_Max(ls,l,Mid,L,R));
	if(Mid<R) res=max(res,ask_Max(rs,Mid+1,r,L,R));
	return res;
}
inline int ask_Min(int id,int l,int r,int L,int R){
	if(l>=L&&r<=R) return mi[id];
	int Mid=(l+r)>>1,res=INF;
	if(Mid>=L) res=min(res,ask_Min(ls,l,Mid,L,R));
	if(Mid<R) res=min(res,ask_Min(rs,Mid+1,r,L,R));
	return res;
}
inline void upt(int id,int l,int r,int pos,int val){
	if(l==r) return sum[id]=mx[id]=mi[id]=val,void();
	int Mid=(l+r)>>1;
	if(Mid>=pos) upt(ls,l,Mid,pos,val);
	else upt(rs,Mid+1,r,pos,val);
	sum[id]=sum[ls]+sum[rs];
	mx[id]=max(mx[ls],mx[rs]);
	mi[id]=min(mi[ls],mi[rs]);
}
inline void opt1(int pos,int val){
	return upt(1,1,n,pos,val),void();
}
inline void opt2(int l,int r,int y){
	auto itr=split(r+1),itl=split(l);
	s.erase(itl,itr);
	return s.insert(Node(l,r,y)),void();
}
int cnt[105];
inline void opt3(int L,int R){
	int ans=INF,sum=0;
	rep(i,1,c,1) cnt[i]=0;
	if(c==1){
		return cout<<ask_Min(1,1,n,L,R)<<'\n',void();
	}
	auto itr=split(R+1),itl=split(L);
	for(auto l=itl,r=itl;r!=itr;r++){
		if(!cnt[r->col])sum++;
		cnt[r->col]++;
		while(sum==c&&cnt[l->col]>1){
			cnt[l->col]--;
			if(cnt[l->col]==0) sum--;
			l++;
		}
		if(sum==c)ans=min(ans,ask_Sum(1,1,n,l->rz,r->lz));
	} 
	wr(ans==INF?-1:ans),pr(10);
}
inline void opt4(int L,int R){
	int ans=ask_Max(1,1,n,L,R),sum=0;
	rep(i,1,c,1) cnt[i]=0;
	auto itr=split(R+1),itl=split(L);
	for(auto l=itl,r=itl;r!=itr;r++){
		if(r->rz-r->lz+1>1)sum++;
		cnt[r->col]++;
		while((sum-((l->rz-l->lz+1)>1)-((r->rz-r->lz+1)>1)>0)||cnt[r->col]>1){
			cnt[l->col]--;
			sum-=((l->rz-l->lz+1)>1);
			l++;
		}
//		cout<<"l:"<<l->rz<<" r:"<<r->lz<<" ans:"<<ans<<'\n';
		ans=max(ans,ask_Sum(1,1,n,l->rz,r->lz));
	} 
	wr(ans),pr(10);
}
signed main(){
	n=read();m=read();c=read();
	rep(i,1,n,1) a[i]=read();
	rep(i,1,n,1) b[i]=read(),s.insert(Node(i,i,b[i]));
	build(1,1,n);
	rep(i,1,m,1){
		int opt=read();
		if(opt==1){
			int x=read(),y=read();
			opt1(x,y);
		}
		if(opt==2){
			int l=read(),r=read(),y=read();
			opt2(l,r,y);
		}
		if(opt==3){
			int l=read(),r=read();
			opt3(l,r);
		}
		if(opt==4){
			int l=read(),r=read();
			opt4(l,r);
		}
	} 
	return 0;
}
/*

*/
  1. P2391 白雪皑皑
    版子
#include<bits/stdc++.h>
#define ddq set<Node>::iterator
#define int long long
#define fi first
#define se second
using namespace std;
const int M=2e5+110;
inline int read(){
	int sum=0,k=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')k=-1;c=getchar();
	}while(c>='0'&&c<='9'){sum=sum*10+c-48;c=getchar();
	}return sum*k;
}
struct Node{
	int lz,rz;mutable int val;
	Node(int lz,int rz=0,int val=0):lz(lz),rz(rz),val(val){};
	inline bool operator<(const Node &a)const{
		return lz<a.lz;	
	}
};set<Node>s;
inline auto split(int pos){// 
	auto it=s.lower_bound(Node(pos));//查询pos所在区间 
	if(it!=s.end()&&it->lz==pos) return it;//pos是该区间开头时 
	it--;//将it往前挪 
	if(it->rz<pos) return s.end();//psos太大,直接返回s的最后 
	int l=it->lz,r=it->rz,w=it->val;
	s.erase(it);//原来的区间直接删掉 
	s.insert(Node(l,pos-1,w));//分割成两个小区间 
	return s.insert(Node(pos,r,w)).first;
}
inline void gto(int l,int r,int w){//将区间l~r变成整块值为w的块
	auto itr=split(r+1),itl=split(l);//找到左右端点
	s.erase(itl,itr);//删除原区间
	s.insert(Node(l,r,w));//加入新区间
}
signed main(){
	int n=read(),m=read(),p=read(),q=read();
	s.insert(Node(1,n,0));
	for(int i=(n<m)?m-n:1;i<=m;i++){
		int l=(i*p+q)%n+1,r=(i*q+p)%n+1;
		if(l>r) swap(l,r);
		gto(l,r,i);
	}
	ddq itr=split(n+1),itl=split(1);
	for(ddq it=itl;it!=itr;it++){
		int sum=it->rz-it->lz+1,va=it->val;
		for(int i=1;i<=sum;i++) printf("%lld\n",va);
	}
	return 0;
}
posted @ 2025-07-17 20:20  rerecloud  阅读(26)  评论(1)    收藏  举报