zoukankan      html  css  js  c++  java
  • [模拟赛]模拟赛集合。

    #A1

    A 卡利班

    发现其任意时刻其结构为一颗树,而 \(f(x)\) 即为这颗树的直径 \((a,b)\) 两端点到 \(x\) 的最大值。

    我们要做的就是动态合并两颗树。

    可以使用 \(LCT\) ,复杂度 \(O(nlogn)\)

    如果不会 \(LCT\) 的话建议使用启发式合并,暴力遍历小的那边,暴力更新\(dep\)和倍增数组。

    A 卡利班
    #include<iostream>
    #include<cstdio>
    #define ll long long 
    #define N 3000005
    
    //___________________
    
    ll f[N],c[N][2],siz[N],st[N];
    bool ri[N];
    
    #define l(x) c[x][0]
    #define r(x) c[x][1]
    
    inline bool nroot(int x){return l(f[x]) == x || r(f[x]) == x;}
    
    inline void up(int x){siz[x] = (siz[l(x)] + siz[r(x)] + 1);}
    
    inline void pushr(int x){std::swap(l(x),r(x));ri[x] ^= 1;}
    
    inline void pushdown(int x){
    	if(ri[x]){
    		if(l(x))pushr(l(x));
    		if(r(x))pushr(r(x));
    		ri[x] = 0;
    	} 
    }
    
    inline void rotate(int x){
    	int y = f[x],z = f[y],k = r(y) == x,w = c[x][!k];
    	if(nroot(y))
    	c[z][r(z) == y] = x;c[x][!k] = y;c[y][k] = w;
    	if(w)
    	f[w] = y;f[y] = x;f[x] = z;
    	up(y);up(x);
    }
    
    inline void splay(int x){
    	ll y = x,z = 0;
    	st[++z] = y;
    	while(nroot(y))st[++z] = y = f[y];
    	while(z)pushdown(st[z -- ]);
    	while(nroot(x)){
    		ll y = f[x],z = f[y];
    		if(nroot(y))
    		rotate((l(y) == x) ^ (l(z) == y) ? x : y);
    		rotate(x);
    	}
    	up(x);
    }
    
    inline void access(int x){
    	for(int y = 0;x;x = f[y = x])
    	splay(x),r(x) = y,up(x);
    }
    
    inline void makeroot(int x){access(x),splay(x),pushr(x);}
    
    inline void split(int x,int y){makeroot(x),access(y),splay(y);}
    
    inline void link(int x,int y){makeroot(x);f[x] = y;}
    
    //__________________LCT
    
    ll fa[N],l[N],r[N];
    
    inline ll find(int x){return (fa[x] == x) ? x : fa[x] = find(fa[x]);}
    
    inline void merge(int x,int y){//x -> y
    	ll ans = 0,ansl,ansr;
    	fa[x] = y;
    	split(l[x],r[x]);
    	if(siz[r[x]] - 1 > ans)
    	ans = siz[r[x]] - 1,ansl = l[x],ansr = r[x];
    
    	split(l[y],r[x]);
    	if(siz[r[x]] - 1 > ans)
    	ans = siz[r[x]] - 1,ansl = l[y],ansr = r[x];
    	
    	split(l[x],r[y]);
    	if(siz[r[y]] - 1 > ans)
    	ans = siz[r[y]] - 1,ansl = l[x],ansr = r[y];
    
    	split(l[y],r[y]);
    	if(siz[r[y]] - 1 > ans)
    	ans = siz[r[y]] - 1,ansl = l[y],ansr = r[y];	
    
    	split(l[x],l[y]);
    	if(siz[l[y]] - 1 > ans)
    	ans = siz[l[y]] - 1,ansl = l[x],ansr = l[y];	
    
    	split(r[x],r[y]);
    	if(siz[r[y]] - 1 > ans)
    	ans = siz[r[y]] - 1,ansl = r[x],ansr = r[y];			
    
    	l[y] = ansl,r[y] = ansr;
    	
    //	std::cout<<x<<" "<<y<<" "<<l[y]<<" "<<r[y]<<std::endl;
    }
    
    //__________________DSU
    
    ll n,q,type,last;
    
    int main(){
    //	freopen("A.in","r",stdin);
    //	freopen("A.out","w",stdout);
    	scanf("%lld",&type);
    	scanf("%lld%lld",&n,&q);
    	for(int i = 1;i <= n;++i)
    	fa[i] = l[i] = r[i] = i;
    	while(q -- ){
    		ll opt,u,v;
    		scanf("%lld",&opt);
    		if(opt == 1){
    			scanf("%lld%lld",&u,&v);
    			u ^= type * last;
    			v ^= type * last;
    			link(u,v);
    			merge(find(u),find(v));
    		}else{
    			scanf("%lld",&u);
    			u ^= type * last;
    			ll al = l[find(u)],ar = r[find(u)];
    			ll ans = 0;
    //			std::cout<<al<<" "<<ar<<std::endl;
    			split(al,u);
    			ans = std::max(ans,siz[u] - 1);
    			split(ar,u);
    			ans = std::max(ans,siz[u] - 1);
    			std::cout<<(last = ans)<<std::endl;
    		}
    	}
    }
    
    

    B. M-IV-Y

    对所有颜色的位置维护其最前,最后两个位置,并分别处理,然后静态答案为\(A\)的数在\(B\)中的逆序对数。

    考虑把一个操作看做从一个颜色集合中删除一个数,然后加入一个颜色集合。

    然后可能对颜色集合的最前最后产生影响,所以又变成了从\(A,B\)中加入,删除点。

    考虑有修改操作的二维数点,CDQ分治。

    C. 博福斯 TRV

    不会可持久平衡树。
    暴力六十不好吗。

    #A3

    A. 搞颜色

    考虑拆贡献到每个颜色。

    对每两个点夹住的区间,根据其长度进行一个区间等差数列加,用两颗BIT维护。

    A. 搞颜色
    #include<bits/stdc++.h>
    #define ll long long 
    #define N 300005
    
    int n,m;
    int a[N];
    
    inline int read(){
    	int ans = 0,f = 1;
    	char a = getchar();
    	while(a != '-' && !(a <= '9' && a >= '0'))
    	a = getchar();
    	while(a <= '9' && a >= '0')
    	ans = (ans << 1) + (ans << 3) + (a - '0'),a = getchar();
    	return f * ans; 
    } 
    
    std::set<int>S[N];
    
    ll T[N];//BIT
    ll B[N];//Tag
    
    #define lowbit(x) (x & -x)
    
    inline void addT(int x,int p){
    	for(int i = x;i <= n;i += lowbit(i))
    	T[i] += p;
    }
    
    
    inline void addB(int x,int p){
    	for(int i = x;i <= n;i += lowbit(i))
    	B[i] += p;	
    }
    
    
    inline ll QT(int x){
    	ll ans = 0;
    	for(int i = x;i;i -= lowbit(i))
    	ans = ans + T[i];
    	return ans;
    }
    
    inline int QB(int x){
    	int ans = 0;
    	for(int i = x;i;i -= lowbit(i))
    	ans = ans + B[i];
    	return ans;
    }
    
    #define IT std::set<int>::iterator
    
    inline void Add(int len,int opt){//长度,符号 
    	addT(1,len * opt);
    	addT(len + 1,-1 * len * opt);
    	addB(1,1 * opt);
    	addB(len + 1,-1 * opt);
    }
    
    inline void pre(){//first_ans
    	for(int i = 1;i <= n;++i){
    //		std::cout<<i<<" "<<std::endl;
    		IT it = S[i].begin();
    		++ it;
    		IT end = S[i].end();
    		while(it != S[i].end()){
    			IT las = prev(it);
    //			std::cout<<*las<<" "<<*it<<" "<<(*it - *las - 1)<<std::endl;				
     			Add(*it - *las - 1,1);
     			++ it;
    		}		
    	}
    }
    
    inline void change(int x,int w){
    	IT it = S[a[x]].lower_bound(x);
    	IT las,nex;
    	nex = ++it;
    	-- it;
    	las = prev(it);
    	Add(*it - *las - 1,-1);
    	Add(*nex - *it - 1,-1);
    	Add(*nex - *las - 1,1);
    	S[a[x]].erase(x);
    	a[x] = w;
    	S[a[x]].insert(x);
    	it = S[a[x]].lower_bound(x);
    	nex = ++it;
    	-- it;
    	las = prev(it);
    	Add(*it - *las - 1,1);
    	Add(*nex - *it - 1,1);
    	Add(*nex - *las - 1,-1);	
    }
    
    int main(){
    //	freopen("q.in","r",stdin);
    //	freopen("q.out","w",stdout);
    	n = read(),m = read(); 
    	for(int i = 1;i <= n;++i){
    		a[i] = read();
    		S[a[i]].insert(i);
    	}
    	for(int i = 1;i <= n;++i){
    		S[i].insert(0);
    		S[i].insert(n + 1);
    	}
    	pre();	
    	while(m -- ){
    		int opt,x,w;
    		opt = read();
    		if(opt == 2){
    			x = read();
    			std::cout<<1ll * (n - x + 1) * n - (QT(x) - 1ll * QB(x) * (x - 1))<<std::endl;			
    		}
    		else{
    			x = read(),w = read();
    			change(x,w);
    		}	
    	}
    }
    

    B. 匹配

    remake成功了。

    高消一下,发现设\(f_i = a_{i,i}\),所以第\(i\)行,只有\(f_i\)\(0\)两个取值。
    当且仅当\(j \in i\)\(a_{i,j} = f_i\)
    所以\(\sum_{k\in i}f_k = a_i\)

    考虑归纳法证明其,考虑第\(i\)行减去所有子集\(k\)对应的行消元结果,\(\sum_{k\in i}f_k[k\in j] = \sum_{k \in (i \& j)}f_k(k \neq i)\)

    \(i \notin j\),则原式\(\sum_{k\in i\& j}f_k = a_{i \& j}\)

    否则\(\sum_{k \in i} f_k = a_i - f_i(i \neq k)\)

    考虑\(\sum_{k \in i}f_k = a_i\),可以推出\(a\)\(f\)高维前缀和的结果,做一次高维差分,一次FMT可以得到答案。

    复杂度\(O(nlogn)\).

    B. 匹配
    #include<bits/stdc++.h>
    #define ll long long 
    #define mod 998244353
    #define N 1000005
    
    ll ans = 1; 
    
    ll a[N];
    
    int n;
    
    inline void FWT_or(ll *f,int type){
    	for(int mid = 1;mid < n;mid <<= 1){
    		for(int block = mid << 1,j = 0;j < n;j += block)
    		for(int i = j;i < j + mid;++i)
    		f[i + mid] = (f[i + mid] + f[i] * type + mod) % mod; 
    	}	
    }
    
    int main(){
    //	freopen("q.in","r",stdin);
    //	freopen("q.out","w",stdout);
    	scanf("%d",&n);
    	for(int i = 0;i < n;++i)
    	scanf("%lld",&a[i]);
    	FWT_or(a,-1);
    	for(int i = 0;i < n;++i)
    	ans = ans * a[i] % mod; 
    	std::cout<<ans<<std::endl;
    }
    

    C. 蹦蹦炸弹

    投出带来无限快乐的蹦蹦炸弹!

    考虑我们使用\(krasual\)

    我们设\(a_i\)\(i\)的联通块编号。

    考虑如果有连边则\([l1,r1],[l2,r2]\)有不同。

    hash,二分直接找到要改的地方。

    每次都会加一条边,只会加\(n - 1\)条。

    然后考虑更新联通块编号。

    即我们启发式合并暴力修改一边的编号。

    是傻逼题,可惜我也是傻逼。

    C. 蹦蹦炸弹
    #include<bits/stdc++.h>
    #define ll long long 
    #define N 100005
    #define mod 998244353
    #define M 500005
    
    int n,m;
    
    int fa[N];
    
    std::set<int>S[N];
    
    ll base[N],inv[N];
    
    inline ll pow(ll a,ll b){
    	ll ans = 1;
    	while(b){
    		if(b & 1) ans = ans * a % mod;
    		a = a * a % mod;
    		b >>= 1;
    	}
    	return ans;
    }
    
    ll T[N];
    
    #define lowbit(x) (x & -x)
    
    inline void add(int x,ll p){
    	for(int i = x;i <= n;i += lowbit(i))
    	T[i] = (T[i] + p + mod) % mod;
    }
    
    inline ll find(int x){
    	ll ans = 0;
    	for(int i = x;i;i -= lowbit(i))
    	ans = (ans + T[i]) % mod;
    	return ans;
    }
    
    inline ll Hash(int l,int r){
    	return (find(r) - find(l - 1) + mod) % mod * inv[l] % mod; 
    }
    
    struct P{
    	int l1,l2,len,w;
    }e[M];
    
    bool operator < (P a,P b){
    	return a.w < b.w;
    }
    
    ll ans = 0;
    
    int cnt = 0;
    
    #define IT std::set<int>::iterator 
    
    inline void merge(int x,int y){
    	if(S[x].size() > S[y].size())std::swap(x,y);//x -> y
    	IT it = S[x].begin();
    	while(it != S[x].end()){
    		add(*it,-1 * base[*it] * x % mod);
    		add(*it,base[*it] * y % mod);
    		fa[*it] = y;
    		S[y].insert(*it);
    		++it;
    	}
    }
    
    inline bool check(int l1,int r1,int l2,int r2){
    //	std::cout<<"["<<l1<<" "<<r1<<"]"<<"["<<l2<<" "<<r2<<"]"<<std::endl;	
    //	std::cout<<Hash(l1,r1)<<" "<<Hash(l2,r2)<<std::endl; 
    	if(Hash(l1,r1) == Hash(l2,r2) || cnt == n - 1)
    	return 0;
    	#define mid1 ((l1 + r1) >> 1)
    	#define mid2 ((l2 + r2) >> 1)
    	while(l1 != r1){
    		if(Hash(l1,mid1) == Hash(l2,mid2))
    		l1 = mid1 + 1,l2 = mid2 + 1;
    		else
    		r1 = mid1,r2 = mid2;
    //		std::cout<<"["<<l1<<" "<<r1<<"]"<<"["<<l2<<" "<<r2<<"]"<<std::endl;
    	}
    //	std::cout<<"ADD"<<"["<<l1<<" "<<r1<<"]"<<"["<<l2<<" "<<r2<<"]"<<std::endl;
    	merge(fa[l1],fa[l2]);
    	return 1;
    }
    
    int main(){
    //	freopen("q.in","r",stdin);
    //	freopen("q.out","w",stdout);	
    	scanf("%d%d",&n,&m);
    	for(int i = 1;i <= n;++i)
    	fa[i] = i,S[i].insert(i);
    	base[0] = 1;
    	for(int i = 1;i <= n;++i)
    	base[i] = base[i - 1] * 10 % mod;
    	for(int i = 1;i <= n;++i)
    	add(i,fa[i] * base[i] % mod);
    	inv[n] = pow(base[n],mod - 2);
    	for(int i = n - 1;i >= 0;--i)
    	inv[i] = inv[i + 1] * 10 % mod;
    	for(int i = 1;i <= m;++i){
    		scanf("%d%d%d%d",&e[i].l1,&e[i].l2,&e[i].len,&e[i].w);
    	}
    	std::sort(e + 1,e + m + 1);
    	for(int i = 1;i <= m;++i){
    //		std::cout<<e[i].l1<<" "<<e[i].l2<<" "<<e[i].len<<" "<<e[i].w<<std::endl; 
    //		check(e[i].l1,e[i].l1 + e[i].len - 1,e[i].l2,e[i].l2 + e[i].len - 1); 
    		while(check(e[i].l1,e[i].l1 + e[i].len - 1,e[i].l2,e[i].l2 + e[i].len - 1))
    		ans += e[i].w,cnt ++ ;
    	}
    	std::cout<<ans<<std::endl; 
    }
    
    /*
    5 3
    1 3 2 5
    2 3 2 3
    4 5 1 1
    */
    
  • 相关阅读:
    【JAVA基础】private 的使用
    【nginx】配置文件(模块、反向代理、负载均衡、动静分离)
    【Nginx】命令行安装
    【UNIAPP】websocte实现,功能:指定房间聊天,匿名进入 功能,文字与图片
    【前端JS】input对象图片在线转base64
    【UNIAPP】上传视频,进度条的前台与后端
    【IO阻塞异步】协程使用异步,异步爬虫,异步数据库操作
    【装饰器】原理以及基础使用
    可编程网络DataPath 及XDP
    gitlab 代码协作流程
  • 原文地址:https://www.cnblogs.com/dixiao/p/15711218.html
Copyright © 2011-2022 走看看