数据结构进阶未完成版本

数据结构进阶

并查集

一些基本的操作

get(int x)
{
		if(fa[x] == x) return x;
  	return fa[x] = get(fa[x])
}
merge(int x,int y)
{
  fa[get(x)] = get(y);
  return;
}

程序自动分析

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n;
int fa[N * 2];
map<int ,int >num;
int cnt;
vector<pair<int ,int > >deny;
int get(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = get(fa[x]);
}
void merge(int x,int y)
{
	fa[get(x)] = get(y);
}
int main()
{
	int T;
	cin >> T;
	while(T)
	{
		deny.clear();
	    num.clear();
		T --;
		cin >> n;
		cnt = 0;
		int a,b,op;
		for(int i = 1;i <= N * 2;i ++) fa[i] = i;
		for(int i = 1;i <= n;i ++)
		{
			scanf("%d%d%d",&a,&b,&op);
 			if(num.find(a) == num.end()) num[a] = ++ cnt;
 			if(num.find(b) == num.end()) num[b] = ++ cnt;//离散化
 			int aa = num[a],bb = num[b];
// 			cout << aa << " " << bb << endl;
 			if(op == 1)
 					merge(aa,bb);
 			else
 				deny.push_back({aa,bb});
		}
		bool flag = 1;
		for(int i = 0;i < deny.size();i ++)
		{
			if(get(deny[i].first) == get(deny[i].second))
				{
					printf("NO\n");flag = 0;break;
				}
		}
		if(flag)
		printf("YES\n");
	}
	return 0;
}

下面这种手动离散化会快一点

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n;
int fa[N * 2];
int figure[N * 2];
int cnt;
struct{
	int a,b,op;
}num[N];
int get(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = get(fa[x]);
}
void merge(int x,int y)
{
	fa[get(x)] = get(y);
}
int main()
{
	int T;
	cin >> T;
	while(T)
	{
		T --;
		cin >> n;
//		cnt = 0;
		int a,b,op;
		for(int i = 1;i <= N * 2;i ++) fa[i] = i;
		for(int i = 1;i <= n;i ++)
			scanf("%d%d%d",&num[i].a,&num[i].b,&num[i].op),figure[i] = num[i].a,figure[i + n] = num[i].b;
		sort(figure + 1,figure + 2 * n + 1);
		cnt = unique(figure + 1,figure + 2 * n + 1) - (figure + 1);
		for(int i = 1;i <= n;i ++)
		{
			if(num[i].op == 1)
			{
				int aa = lower_bound(figure + 1,figure + cnt + 1,num[i].a) - figure;
				int bb = lower_bound(figure + 1,figure + cnt + 1,num[i].b) - figure;
				merge(aa,bb);
			}
		}
		bool flag = 1;
		for(int i = 1;i <= n;i ++)
		{
			if(num[i].op == 0)
				{
					int aa = lower_bound(figure + 1,figure + cnt + 1,num[i].a) - figure;
					int bb = lower_bound(figure + 1,figure + cnt + 1,num[i].b) - figure;
					if(get(aa) == get(bb))
					{
						printf("NO\n");flag = 0;break;
					}
				}
		}
		if(flag)
		printf("YES\n");
	}
	return 0;
}

并查集主要用来判断两个元素是否属于同一类,广泛一点可以推到判断一种关系

奇偶游戏

首先分析题意,如果说l~r之间的数有偶数个,那么前l - 1和前r个数的奇偶性相等。奇数个则相反。

然后我们可以得到,x1和x2奇偶性相同,x2和x3奇偶性相同,那么x1和x3奇偶性也相同。

x1和x2奇偶性不同,x2和x3奇偶性相同,x1和x3奇偶性也不同

以此类推,就可以类比异或算法,0 ^ 0 = 0(两组奇偶性相同),1 ^ 1(两组的奇偶性都不相同) = 0,0 ^ 1(两组的奇偶性相反) = 1

所以这个有传递性

边带权算法

边带权,就是把每条边的距离设为0或1,分别代表相同和不同.

当发现x和y不属于同一个集合时,合并时注意根之间的长度

x和y属于同一个集合时,判断他们分别到根节点的异或值与给出的是否对应.

#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
struct {
	int l,r,ans;
}query[N];
int a[N * 2],fa[N * 2],d[N * 2],n,m,t;


void read_discrete()//读入并离散化
{
	cin >> n >> m;
	for(int i = 1;i <= m;i ++)
	{
		char str[5];
		scanf("%d%d%s",&query[i].l,&query[i].r,str);
		if(str[0] == 'o') query[i].ans = 1;
		else query[i].ans = 0;
		a[++ t] = query[i].l - 1;
		a[++ t] = query[i].r;
	}
	sort(a + 1,a + t + 1);
	n = unique(a + 1,a + t + 1) - a - 1;
}


int get(int x)
{
	if(x == fa[x]) return x;
	int root = get(fa[x]);
	d[x] ^= d[fa[x]];
	return fa[x] = root;
}
int main()
{
	read_discrete();
	for(int i = 1;i <= n;i ++) fa[i] = i;
	for(int i = 1;i <= m;i ++)
	{
		int x = lower_bound(a + 1,a + n + 1,query[i].l - 1) - a;
		int y = lower_bound(a + 1,a + n + 1,query[i].r) - a;
		int p = get(x),q = get(y);
		if(p == q)
		{
			if((d[x] ^ d[y]) != query[i].ans)
			{
				cout << i - 1;
				return 0;
			}
		}
		else
		{
			fa[p] = q;
			d[p] = d[x] ^ d[y] ^ query[i].ans;//这里异或两个点到根的值和奇偶关系值
		}
	}
	cout << m;
	return 0;
}

扩展域算法
#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
struct {
	int l,r,ans;
}query[N];
int a[N * 2],fa[N * 2 + 10],n,m,t;


void read_discrete()
{
	cin >> n >> m;
	for(int i = 1;i <= m;i ++)
	{
		char str[5];
		scanf("%d%d%s",&query[i].l,&query[i].r,str);
		if(str[0] == 'o') query[i].ans = 1;
		else query[i].ans = 0;
		a[++ t] = query[i].l - 1;
		a[++ t] = query[i].r;
	}
	sort(a + 1,a + t + 1);
	n = unique(a + 1,a + t + 1) - a - 1;
}


int get(int x)
{
	if(x == fa[x]) return x;
	return get(fa[x]);
}
void merge(int x,int y)
{
	fa[get(x)] = get(y);
	return ;
}
int main()
{
	read_discrete();
	for(int i = 1;i <= n;i ++) fa[i] = i,fa[i + N] = i + N;
	for(int i = 1;i <= m;i ++)
	{
		int x = lower_bound(a + 1,a + n + 1,query[i].l - 1) - a;
		int y = lower_bound(a + 1,a + n + 1,query[i].r) - a;
		if(query[i].ans == 1)
		{
			if(get(x) == get(y))
			{
				cout << i - 1;
				return 0;
			}
			merge(x + N , y);
			merge(x,y + N);
		}
		else
		{
			if(get(x + N) == get(y))
			{
				cout << i - 1;
				return 0;
			}
			merge(x , y);
			merge(x + N,y + N);
		}
	}
	cout << m;
	return 0;
}

树状数组

树状数组模板1

#include<bits/stdc++.h>
using namespace std;

const int N = 5 * 1e5 + 2;

int n,m;
int c[N];
int a[N];
int lowbit(int x)
{
	return x & -x;
}
void add(int x,int i)
{
	for(;x <= n;x += lowbit(x)) c[x] += i;
}//添加值

int get(int l,int r)
{
	int sum = 0;
	for(;l;l -= lowbit(l)) sum -= c[l];
	for(;r;r -= lowbit(r)) sum += c[r];
	return sum;
}//得到区间值
int main()
{
	
	cin >> n >> m;
	for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
	
	for(int i = 1;i <= n;i ++)
	{
		c[i] += a[i];
		if(i + lowbit(i) <= n)
			c[i + lowbit(i)] += c[i];
	}//初始化树状数组
	for(int i = 1;i <= m;i ++)
	{
		int d,a,b;
		scanf("%d%d%d",&d,&a,&b);
		if(d == 1)
			add(a,b);
		else
			printf("%d\n",get(a - 1,b));
	}
	
}

树状数组模板2

#include<bits/stdc++.h>
using namespace std;

const int N = 500009;

int n,m;
int c[N];
int a[N];
int lowbit(int x)
{
	return x & -x;
}
void add(int x,int i)
{
	for(;x <= n;x += lowbit(x)) c[x] += i;
}
int get(int x)
{
	int sum = 0;
	for(;x;x -= lowbit(x)) sum += c[x];
	return sum;
}
int op,x,y,k;
int main()
{
	
	cin >> n >> m;
	for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
	for(int i = 1;i <= m;i ++)
	{
		scanf("%d",&op);
		if(op == 1)
		{
			scanf("%d%d%d",&x,&y,&k);
			add(x,k);
			add(y + 1,-k);
		}
		else
		{
			scanf("%d",&k);
			printf("%d\n",a[k] + get(k));
		}
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值