算法分析与设计

1. 线段树

#include<iostream>
#include<cstdio>
#include<algorithm> 
#include<cmath>
#include<stack>
#include<cstring>
#include<vector>

using namespace std;
int tree[1005 * 4], a[1005];
int lazy[1005 * 4];
//初始化线段树:当前处理p号,对应空间为[l,r]空间
void build(int p, int l, int r)
{
	if (l == r)//到达叶子节点,直接赋值
	{
		tree[p] = a[l];//a中存储数据
		return;
	}
	int mid = (l + r) / 2;
	build(p * 2, l, mid);//递归构造左子树
	build(p * 2 + 1, mid + 1, r);//递归构造右子树
	tree[p] = tree[p * 2] + tree[p * 2 + 1];//合并左右子树,这里的合并逻辑是相加
}

//将lazy-tag向下传递一层
void push_down(int p, int l, int r)
{
	int mid = (l + r) / 2;
	lazy[p * 2] += lazy[p];
	lazy[p * 2 + 1] += lazy[p];
	tree[p * 2] += lazy[p] * (mid - l + 1);
	tree[p * 2 + 1] += lazy[p] * (r - mid);
	lazy[p] = 0;
}

//区间查找:当前节点p点,对应空间[l,r];查询[x,y]区间和
int find_interzone(int p, int l, int r, int x, int y)
{
	int mid = (l + r) / 2;
	int ans = 0;

	if (r < x || l > y) //没有交集,返回0
		return 0;
	if (x <= l && y >= r)//[x,y]将[l,r]完全包含,返回区间值
		return tree[p];

	push_down(p, l, r);  //如果使用lazy-tag需要加上这个
	if (x <= mid)//左儿子和这个区间有交集,搜索左儿子
		ans += find_interzone(p * 2, l, mid, x, y);
	if (y > mid)//右儿子和这个区间有交集,搜索右儿子
		ans += find_interzone(p * 2 + 1, mid + 1, r, x, y);
	return ans;
}

//单点更新:当前节点p点,对应空间[l,r];将第key号点的值改为value
void update_dot(int p, int l, int r, int key, int value)
{
	if (l == r)//在叶子节点中找到key点
	{
		tree[p] = value;
		return;
	}
	int mid = (l + r) / 2;
	if (key <= mid) //若key在左子树,递归查找
		update_dot(p * 2, l, mid, key, value);
	if (key > mid)//若key在右子树,递归查找
		update_dot(p * 2 + 1, mid + 1, r, key, value);
	tree[p] = tree[p * 2] + tree[p * 2 + 1];//回溯时修改每个节点的值
}

//区间更新:当前节点p,区间为[l,r],目标区间[x,y],操作是每个值加k
void update_interzone(int p, int l, int r, int x, int y, int k)
{
	if (l > y || r < x)//[l,r]和[x,y]无交集,剪枝
		return;
	else if (l >= x && r <= y)//[l,r]被[x,y]完全包含
	{
		tree[p] += (r - l + 1) * k;//暂时不下放,节点p得到其子树的所有k
		if (r > l) lazy[p] += k; //如果不是叶子节点,lazy-tag更新
	}
	else //[l,r]与[x,y]有交集
	{
		push_down(p, l, r);//需要操作子树,赶紧下放k
		int mid = (l + r) / 2;
		if(x<=mid)		update_interzone(p * 2, l, mid, x, y, k);
		if(y>mid)       update_interzone(p * 2 + 1, mid + 1, r, x, y, k);
		tree[p] = tree[p * 2] + tree[p * 2 + 1];//回溯时更新当前节点
	}
}

//单点查询:当前节点p,区间为[l,r],目标点key
int find_dot(int p, int l, int r, int key)
{
	if (l == r)
		return tree[p];

	push_down(p, l, r);
	int mid = (l + r) / 2;
	if (key <= mid)
		find_dot(p * 2, l, mid, key);
	else if (key > mid)
		find_dot(p * 2 + 1, mid + 1, r, key);
}


int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	build(1, 1, n);
	for (int i = 0; i < m; i++)
	{
		int type;	cin >> type;
		if (type == 1)
		{
			int x, k;
			cin >> x >> k;
			update_dot(1, 1, n, x, k);
		}
		else
		{
			int x;
			cin >> x;
			printf("%d\n", find_dot(1, 1, n, x));
		}
	}
}


2.树状数组

#include<iostream>
#include<cstdio>
#include<algorithm> 
#include<cmath>
#include<stack>
#include<cstring>
#include<vector>

using namespace std;

int tree[2000005] = { 0 };

//最低位“1”的所在位置
int lowbit(int x)
{
	return x & (-x);
}
//前缀和:求前n项和
long long sums(int n)
{
	long long ans = 0;
	for (int pos = n; pos > 0; pos -= lowbit(pos))
	{
		ans += tree[pos];
	}
	return ans;
}

//单点修改:将i号位置的元素加上k,树状数组的长度为len
void update(int i, int k, int len)
{
	for (int pos = i; pos <= len; pos += lowbit(pos))
	{
		tree[pos] += k;
	}
}

//区间查询:[l,r]范围的和
long long query(int l, int r)
{
	return sums(r) - sums(l - 1);
}

int tree2[1005][1005];
//二维树状数组单点修改:[x,y]位置上的数加上data,数组大小为n*m
void update_2(int x, int y, int data, int n, int m)
{
	for (int i = x; i <= n; x += lowbit(i))
	{
		for (int j = y; j <= m; j += lowbit(j))
		{
			tree2[i][j] += data;
		}
	}
}

//二维树状数组单点查询:返回tree2[0-x][0-y]之和,数组大小为n*m
int query_2(int x, int y, int n, int m)
{
	int ans = 0;
	for (int i = x; x > 0; x -= lowbit(i))
	{
		for (int j = y; j > 0; j -= lowbit(j))
		{
			ans += tree2[i][j];
		}
	}
	return ans;
}

int main()
{
	int n, m;  cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int temp; cin >> temp;
		update(i, temp, n);
	}
	for (int i = 1; i <= m; i++)
	{
		int tag; cin >> tag;
		if (tag == 1)
		{
			int x, k; cin >> x >> k;
			update(x, k, n);
		}
		if (tag == 2)
		{
			int x, y; cin >> x >> y;
			cout << query(x, y) << endl;
		}
	}
}

3.网络流

#include<iostream>
#include<cstdio>
#include<algorithm> 
#include<cmath>
#include<stack>
#include<cstring>
#include<vector>

#define MAXN 201
#define inf 1<<30
using namespace std;

//Ford-Fulkerson算法
int cap[MAXN][MAXN];
int used[MAXN];

int v_num, e_num;

int dfs(int s, int t, int f)
{
	if (s == t) return f; //到达终点,返回增广路径的流量
	for (int i = 1; i <= v_num; i++)//遍历所有点
	{
		if (!used[i] && cap[s][i] > 0)//i点没有被二次使用 and s到i之间有路径
		{
			used[i] = 1;
			int delta = dfs(i, t, min(f, cap[s][i]));//从i出发去寻找汇点
			if (delta > 0) //如果找到路径,回溯时对路径进行修改
			{
				cap[s][i] -= delta; //正向路径减
				cap[i][s] += delta; //反向路径加
				return delta;
			}
		}
	}
	return 0;
}
int maxflow(int src, int des)
{
	int f = 0, d = 0;
	while (1)
	{
		memset(used, 0, sizeof(used));
		used[1] = 1; //源点被使用
		if (!(d = dfs(src, des, inf)))//没有增广路径了
			return f;
		f += d; //找到一条路,流量增加
	}
}

int main()
{
	int from, to, len;
	while (scanf("%d%d", &e_num, &v_num) != EOF)
	{
		memset(cap, 0, sizeof(cap));
		for (int i = 0; i < e_num; i++)
		{
			scanf("%d%d%d", &from, &to, &len);
			cap[from][to] += len;
		}
		printf("%d\n", maxflow(1, v_num));
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值