AcWing提高算法课Level-3 第四章 高级数据结构

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing提高算法课Level-3 第四章 高级数据结构相关的知识,希望对你有一定的参考价值。

AcWing提高算法课Level-3 第四章 高级数据结构

并查集
AcWing 1250. 格子游戏1167人打卡
AcWing 1252. 搭配购买1064人打卡
AcWing 237. 程序自动分析940人打卡
AcWing 239. 奇偶游戏629人打卡
AcWing 238. 银河英雄传说844人打卡

树状数组
AcWing 241. 楼兰图腾1083人打卡
AcWing 242. 一个简单的整数问题1050人打卡
AcWing 243. 一个简单的整数问题2916人打卡
AcWing 244. 谜一样的牛869人打卡

线段树
AcWing 1275. 最大数1125人打卡
AcWing 245. 你能回答这些问题吗955人打卡
AcWing 246. 区间最大公约数762人打卡
AcWing 243. 一个简单的整数问题2845人打卡
AcWing 247. 亚特兰蒂斯482人打卡
AcWing 1277. 维护序列638人打卡

可持久化数据结构
AcWing 256. 最大异或和388人打卡
AcWing 255. 第K小数428人打卡

平衡树
AcWing 253. 普通平衡树415人打卡
AcWing 265. 营业额统计344人打卡

AC自动机
AcWing 1282. 搜索关键词441人打卡
AcWing 1285. 单词297人打卡

代码

AcWing 1250. 格子游戏1167人打卡

//题意:给出n*n的网格,按顺序m次操作,每次从(x,y)向右或下连画一条边,求第几次时能围成封闭的图形。
//思路:把n*n个坐标看成对应的点(可以用x*n+y映射),问题转换为每次连一条边,求最早何时形成环。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 210;

int fa[maxn*maxn+10];
void init(int n){for(int i = 1; i <= n; i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}

int getid(int x, int y){
	return x*maxn+y;
}

int main(){
	ios::sync_with_stdio(false);
	int n, m;   cin>>n>>m;
	init(maxn*maxn);
	for(int i = 1; i <= m; i++){
		int x, y;  char op;
		cin>>x>>y>>op;
		int a = getid(x,y), b = getid(x+(op=='D'), y+(op=='R'));
		int aa=find(a), bb=find(b);
		if(aa==bb){
			cout<<i<<"\\n";
			return 0;
		}else{
			merge(aa,bb);
		}
	}
	cout<<"draw\\n";
	return 0;
}

AcWing 1252. 搭配购买1064人打卡

//题意:n朵云,每朵有价钱和价值。m个关系,买了u就必须买v。一共有w钱,最大化价值。
//思路:m个关系并查集处理后,得到若干个独立的连通块,把这些块作为物品,计算出价钱和价值,跑01背包即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10010;

int c[maxn], d[maxn];
int dp[maxn];

int fa[maxn+10];
void init(int n){for(int i = 1; i <= n; i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}

int main(){
	ios::sync_with_stdio(false);
	//UnionFindSet
	int n, m, w;  cin>>n>>m>>w;
	for(int i = 1; i <= n; i++)cin>>c[i]>>d[i];//价钱,价值
	init(n);
	for(int i = 1; i <= m; i++){
		int u, v;  cin>>u>>v;  merge(u,v);
	}
	map<int,int>cc, dd;
	for(int i = 1; i <= n; i++){
		cc[find(i)] += c[i];
		dd[find(i)] += d[i];
	}
	vector<pair<int,int> >vc(cc.begin(),cc.end()), vd(dd.begin(),dd.end());
	//01 Pack
	for(int i = 0; i < vc.size(); i++){
		for(int j = w; j >= vc[i].second; j--){
			dp[j] = max(dp[j], dp[j-vc[i].second]+vd[i].second);
		}
	}
	cout<<dp[w]<<"\\n";
	return 0;
}

AcWing 237. 程序自动分析940人打卡

//题意:n个条件,每个条件(xi,xj,e)表示xi==xj或xi!=xj,判断是否有冲突。
//思路:先并查集合并所有xi==xj的数到相同集合,然后跑xi!=xj的判断冲突。因为数字比较大所以先离散化一下。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;

vector<pair<int,int> >eq, uneq;

//离散化
unordered_map<int,int>ma; int cnt = 0;
int mp(int x){
    if(!ma.count(x))ma[x]=++cnt;
    return ma[x];
}

//并查集
int fa[maxn+10];
void init(int n){ for(int i = 1; i <= n; i++)fa[i]=i; }
int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}

int main(){
	ios::sync_with_stdio(false);
	int T;  cin>>T;
	while(T--){
        eq.clear(), uneq.clear();
        cnt = 0;  ma.clear();

		int n;  cin>>n;
		for(int i = 1; i <= n; i++){
            int x, y, e;  cin>>x>>y>>e;
            x = mp(x), y = mp(y);
            if(e==1){
                eq.push_back({x,y});
            }else{
                uneq.push_back({x,y});
            }
        }

        init(cnt);
        for(auto x : eq)merge(x.first, x.second);
        int ok = 1;
        for(auto x : uneq){
            if(find(x.first)==find(x.second)){
                ok = 0; break;
            }
        }
        if(ok==0)cout<<"NO\\n";
        else cout<<"YES\\n";
	}
	return 0;
}

AcWing 239. 奇偶游戏629人打卡

//题意:有一个长为n的01序列(未给出),按顺序给出m次询问的答案,每次回答区间[l,r]中1的个数是奇数还是偶数,求从第几个询问开始冲突。
/*思路:
+ 用s[i]表示原序列的前缀和,那么就可以得到区间[l,r]中1的个数(即s[r]-s[l-1])的奇偶性。
+ 当s[r]-s[l-1]为奇数时,可以推出,s[r]与s[l-1]肯定是一个奇数一个偶数。反之两个肯定都为奇数或者偶数。
+ 用扩展域维护关系的传递性,将每个节点x拆为奇数域与偶数域,分别表示x是奇数和x是偶数,维护合并的时候判断冲突信息即可。
+ 节点范围1e9较大,需要离散化一下。
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;

//离散化
unordered_map<int,int>ma; int cnt = 0;
int mp(int x){
    if(!ma.count(x))ma[x]=++cnt;
    return ma[x];
}

//并查集
int fa[2*maxn+10];
void init(int n){ for(int i = 1; i <= n; i++)fa[i]=i; }
int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}

int main(){
	ios::sync_with_stdio(false);
	int n;  cin>>n;
    int m;  cin>>m;
    init(2*maxn);
    int ans = m; //无矛盾时答案即为问题的数量
    for(int i = 1; i <= m; i++){
        int l, r; string op;  cin>>l>>r>>op;
        l = mp(l-1), r = mp(r);   //sum[l~r]=s[r]-s[l-1];
        if(op=="even"){           //sum[l~r]为偶数,即s[l-1]和s[r]奇偶性相同
            if(find(l+maxn) == find(r)){ //冲突了
                ans = i-1; break;
            }
            merge(l,r);          //s[l]和s[r]都是奇数
            merge(l+maxn,r+maxn);//或者s[l]和s[r]都是偶数
        }else{
            if(find(l)==find(r)){
                ans = i-1; break;
            }
            merge(l+maxn, r);
            merge(l,r+maxn);
        }
    }
    cout<<ans<<"\\n";
	return 0;
}

AcWing 238. 银河英雄传说844人打卡

//带权并查集
//维护每个节点(战舰)到该列舰首的位置和每列战舰的长度
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
typedef long long LL;

int fa[maxn+10];
int sz[maxn], rk[maxn];
void init(int n){for(int i = 1; i <= n; i++)fa[i]=i,sz[i]=1;}
int find(int x){
	if(fa[x]==x)return x;
	else{
		int t = find(fa[x]);
		rk[x] += rk[fa[x]];
		return fa[x]=t;
	}
}
void merge(int x, int y){
	x=find(x);y=find(y);
	if(x!=y){
		fa[x]=y;
		rk[x] += sz[y];
		sz[y] += sz[x];
		sz[x] = 0;
	}
}

int main(){
	ios::sync_with_stdio(false);
	int n = 30000;
	init(n);
	int T;  cin>>T;
	while(T--){
		char op; int a, b;
		cin>>op>>a>>b;
		if(op=='M'){
			merge(a,b);//a整列接到b后面
		}else{
			if(find(a)!=find(b)){
				cout<<"-1\\n";
			}else{
				cout<<abs(rk[a]-rk[b])-1<<"\\n";
			}
		}
	}
	return 0;
}

AcWing 241. 楼兰图腾1083人打卡

//题意:给出一条横轴上的n个点的纵坐标,求有多少个v和∧图形(中间点y值高于两边或低于两边)
//思路:从左向右依次遍历每个数a[i],使用树状数组统计在i位置之前所有比a[i]大的数的个数、以及比a[i]小的数的个数。统计完成后,将a[i]加入到树状数组。
//思路:再从右向左依次遍历每个数a[i],使用树状数组统计在i位置之后所有比a[i]大的数的个数、以及比a[i]小的数的个数。统计完成后,将a[i]加入到树状数组。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2000010;

int a[maxn];
int sm[maxn], bg[maxn];//左边比a[i]小,比a[i]大的数的个数

//树状数组
int n, b[maxn];
void add(int x, int v){ for(int i = x; i <= n; i+=i&(-i))b[i]+=v;}//序列中第x个数加上k
int query(int x){ int ans=0;for(int i=x;i>0;i-=i&(-i))ans+=b[i];return ans;}//查询序列前x个数的和

int main(){
	ios::sync_with_stdio(false);
	cin>>n;
    for(int i = 1; i <= n; i++)cin>>a[i];
    for(int i = 1; i <= n; i++AcWing算法基础课,提高课,进阶课目录

算法提高课——搜索

acwing里的yxc是谁?

acwing是闫学灿自己写的吗

AcWing基础算法课Level-2 第一讲 基础算法

AcWing进阶算法课Level-4 第七章 基础算法