【扫描线法】&& poj 1177 && hdu 1828

本文详细介绍了如何使用扫描线算法结合线段树解决几何问题,具体包括矩形周长并和面积并的计算。通过离散化和线段树维护,实现了高效的事件处理,最终求得所关注的几何量。

    

      可以看看这里: http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html

      为了写扫描线, 大概写了有史以来最丑的线段树了。


      poj 1177 && hdu 1828 都是求矩形周长并,周长并改一改就可以求面积并了。

      其实思想并不复杂,将x维排序,将x维上的2n条线段作为事件,每个事件统计与上个事件之间的所占周长长度。


      统计周长长度有点烦, 在y维上要用线段树维护: 共有多长的线段被覆盖,以及共有多少“团”线段。


      每次加的答案就是 : 覆盖值得改变量 + (当前线段与前一线段的距离) * 2 * (线段"团"数);

 

      至于线段树,离散之后我维护了六个标记(貌似有神犇只要用三个标记+.+),而且合并的时候写的十分丑陋;


      维护了这么六个值: 该区间覆盖最小值,最小值是否在左区间/右区间,最小值出现次数以及团数,以及为了维护最小值而保留的另一个标记。


     反正就是很丑,写了5KB,难得有线段树写的这么丑。


# include <cstdio>
# include <cstdlib>
# include <cmath>
# include <cstring>

using namespace std;

const int maxn = 7000;
int len[maxn*2], old[maxn*2],left[maxn], right[maxn], low[maxn],high[maxn];
int newlow[maxn], newhigh[maxn], num[maxn*2], id[maxn*2];
int bj[maxn*4], tmin[maxn*4], tot[maxn*4], repeat[maxn*4];
bool covl[maxn*4], covr[maxn*4];

int top, mat, ans, h, st, n, i;
 
void sort(int l, int r)
{
	int i = l, j = r, d = num[(l + r) >> 1], dj = id[(l + r) >> 1] % 2,tmp;
	for (;i <= j;)
	{
		for (;(num[i] < d) || (num[i] == d && (id[i] % 2) < dj);i++);
		for (;(num[j] > d) || (num[j] == d && (id[j] % 2) > dj);j--);
		if (i <= j)
		   tmp = num[i], num[i] = num[j], num[j] = tmp,
		   tmp = id[i], id[i] = id[j], id[j] = tmp, i++, j--;
	}
	if (i < r) sort (i, r);
	if (l < j) sort (l, j);
}

void prepare_y()
{
	int i; mat = 1,  top = 0;
	for (i = 1; i <= n; i++)
	{
		num[++top] = low[i], id[top] = i * 2;
		num[++top] = high[i], id[top] = i * 2 +1; 
	}
	sort(1, top);
	for (i = 1; i <= top; i++)
	{
		if (num[i] != num[i - 1]) mat++;
		if ((id[i] & 1) == 0 ) newlow[id[i] >> 1] = mat, old[mat] = low[id[i] >> 1];
		else newhigh[id[i] >> 1] = mat, old[mat] = high[id[i] >> 1]; 
	}
	for (h = 0, st = 1; st <= mat + 1; st <<= 1, h ++);
	for (i = 1; i <= st * 2; i++) len[i] = 1; 
	for (i = 1; i <= mat-1; i++) len[st + i] = old[i+1] - old[i];
	for (i = st-1; i>=1; i--) len[i] = len[i << 1]+ len[(i << 1)+1];
	memset(id, 0, sizeof(id));
	memset(num, 0, sizeof(num));
}

void prepare_x()
{
	top = 0;
	for (i = 1; i <= n; i++)
	{
		num[++top] = left[i], id[top] = i * 2;
		num[++top] = right[i], id[top] = i * 2 +1;
	}
	sort(1, top);
}

void origin()
{
	memset(bj, 0, sizeof(bj));
	memset(tmin, 0, sizeof(tmin));
	memset(covl, true, sizeof(covl));
	memset(covr, true, sizeof(covr));
	for (int i = 1; i <= st * 2; i++) 
	   repeat[i] = 1, tot[i] = 1;
	for (int i = 1; i <= mat; i++)
	   tot[i +st] = len[i+st];
	for (int i = st - 1; i >= 1; i--)
	   tot[i] = tot[i << 1] + tot[(i << 1 )+1];
}

int min(int x, int y)
{
	return x < y ? x: y;
}

void up(int x)
{
	for (; x>= 1; x >>=1)
	{
		tmin[x] = min(tmin[x << 1], tmin[(x << 1) +1]);
		if (tmin[x << 1] == tmin[(x << 1) +1])
		{
			repeat[x] = repeat[x << 1] + repeat[(x << 1) +1] - (covr[x << 1] && covl[(x << 1)+1]);
			tot[x] = tot[x << 1] + tot[(x << 1 )+1];
			covl[x] = covl[x << 1], covr[x] = covr[(x << 1) +1]; 
		}
		else if (tmin[x << 1] < tmin[(x << 1) +1])
		{
			repeat[x] = repeat[x << 1];
			tot[x] = tot[x << 1];
			covl[x] = covl[x << 1], covr[x] = false;
		}
		else
		{
			repeat[x] = repeat[(x << 1)+1];
			tot[x] = tot[(x << 1) +1];
			covr[x] = covr[(x << 1)+1]; covl[x] = false;
		}
	}
}

void down(int x)
{
    int i, now;
    for (i = h; i>0; i--)
    {
		now = x >> i;
		if (bj[now] != 0) 
		{
			bj[now << 1]+= bj[now], bj[(now << 1) +1]+= bj[now];
			tmin[now << 1]+= bj[now], tmin[(now << 1)+1]+= bj[now];
			bj[now]= 0; 
		} 
	}
}

void change(int l, int r, int d)
{
	l = l+st-1, r = r+st+1;
	int ll = l >> 1, rr = r >> 1;
	down(l); down(r);
	for (;(l ^ r) != 1; l >>= 1, r >>= 1)
	{
		if ((l & 1) == 0) bj[l+1]+=d, tmin[l+1]+=d;
		if ((r & 1) == 1) bj[r-1]+=d, tmin[r-1]+=d;
	}
	up(ll); up(rr); 
}

void help()
{
    for (int i = 1; i <= st; i++)
       down(i+st);
}

int main()
{
	freopen("1177.in", "r", stdin);
	freopen("1177.out", "w", stdout);
	while (scanf("%d", &n) != EOF)
	{
	for (i = 1; i <= n; i++)
	   scanf("%d%d%d%d", &left[i], &low[i], &right[i], &high[i]);
	prepare_y();
	prepare_x();
	origin();
	ans = high[id[1] >> 1] - low[id[1] >> 1];
	change(newlow[id[1] >> 1], newhigh[id[1] >> 1]-1, 1);
	for (i = 2; i <= top; i++)
	{
	 	//help();
		int who = id[i] >> 1;
		int a1 = len[1]- tot[1] , a2 = repeat[1];
		if ((who << 1)== id[i]) change(newlow[who], newhigh[who]-1, 1);
		else change(newlow[who], newhigh[who]-1, -1);
		int b1 = len[1]- tot[1] ;
		ans += abs(a1 - b1) + (num[i] - num[i-1]) * 2 * (a2 - 1); 
	}
	printf("%d\n", ans);
    }
	return 0;
}

ps: hdu上居然是多组数据,贡献了六七个wa。


附带一个poj1151 求矩形面积并的, 稍微好些一点;

# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>

using namespace std;

const int maxn = 200;
int  id[maxn];
double num[maxn], left[maxn], right[maxn], low[maxn], high[maxn], old[maxn*2], tot[maxn*4], len[maxn*4];
int  tmin[maxn*4],  bj[maxn*4], newlow[maxn], newhigh[maxn];
int  test, h, st, n, top, mat;
double ans;

void sort(int l, int r)
{
	double d = num[(l + r)>> 1], tmpd;
	int i = l, j = r, tmp,  dj = id[(l + r)>> 1] & 1;
	for (;i <= j;)
	{
		for (;num[i] < d || (num[i] == d && (id[i] & 1) < dj); i++);
        for (;num[j] > d || (num[j] == d && (id[j] & 1) > dj); j--);
		if (i <= j) 
		   tmpd=num[i], num[i]=num[j], num[j]=tmpd,
		   tmp=id[i], id[i]=id[j], id[j]=tmp, i++,j--;	
	}
	if (i < r) sort(i, r);
	if (l < j) sort(l, j); 
}

void prepare_y()
{
	memset(num, 0, sizeof(num));
	memset(id, 0, sizeof(id));
	int i; top = 0; mat = 1;
	for (i = 1; i <= n; i++)
	{
		num[++top] = low[i]; id[top] = i * 2;
		num[++top] = high[i]; id[top] = i * 2 + 1;
	}
	sort(1, top);
	for (i = 1; i <= top; i++)
	{
		if (num[i] != num[i-1]) mat++;
		if ((id[i] & 1) == 0) newlow[id[i] >> 1] = mat, old[mat] = low[id[i] >> 1];
		else newhigh[id[i] >> 1] = mat, old[mat] = high[id[i] >> 1]; 
	}
	for (st = 1, h = 0; st <= mat +1; st <<= 1, h++);
	for (i = 1; i <= st*2; i++) len[i] = 1;
	for (i = 1; i <= mat-1; i++) len[i+st] = old[i+1] - old[i];
	for (i = st-1; i >= 1; i--) len[i] = len[i << 1] + len[(i << 1)+1];
}

void prepare_x()
{
	memset(num, 0, sizeof(num));
	memset(id, 0, sizeof(id));
	int i; top = 0; mat = 1;
	for (i = 1; i <= n; i++)
	{
		num[++top] = left[i], id[top] = i * 2;
		num[++top] = right[i], id[top] = i * 2 +1;
	}
	sort(1, top);
}

void origin()
{
	int i; ans = 0; 
	memset(tmin, 0, sizeof(tmin));
	memset(bj, 0 ,sizeof(bj));
	for (i = 1; i <= st*2; i++) tot[i] = len[i];
}

void read()
{
	int i; scanf("%d", &n);
	for (i = 1; i <= n; i++)
	  scanf("%lf%lf%lf%lf", &left[i], &low[i], &right[i], &high[i]);
	prepare_y();
	prepare_x();
	origin();
}

void down(int x)
{
	int i;
	for (i = h; i > 0; i--)
	{
		int now = x >> i;
		if (bj[now] != 0)
		{
			bj[now << 1]+= bj[now]; bj[(now << 1)+1]+= bj[now];
			tmin[now << 1]+=bj[now]; tmin[(now << 1)+1]+= bj[now];
			bj[now] = 0; 
		}
	}
}

int min(int x, int y)
{
	return x < y ? x:y ;
}

void up(int x)
{
	for (;x > 0; x >>=1)
	{
		tmin[x] = min(tmin[x << 1], tmin[(x << 1)+1]);
        if (tmin[x << 1] == tmin[(x << 1)+1]) tot[x] = tot[x << 1] + tot[(x << 1)+1];
        else if (tmin[x << 1] < tmin[(x << 1)+1]) tot[x] = tot[x << 1];
        else  tot[x] = tot[(x << 1)+1];
	}
}

void change(int l, int r, int d)
{
	l = l+st-1; r= r+st+1; 
	int ll = l >> 1, rr = r >> 1;
	down(l); down(r);
	for (;(l ^ r) != 1; l>>=1, r>>=1)
	{
		if ((l & 1) == 0) tmin[l+1]+= d, bj[l+1]+= d;
		if ((r & 1) == 1) tmin[r-1]+= d, bj[r-1]+= d;
	}
	up(ll); up(rr);
}

int i; 
int main()
{
	freopen("1151.in", "r", stdin);
	freopen("1151.out", "w", stdout);
	for (test = 1;;test++)
	{
		read();
		if ( n == 0) break;
		change(newlow[id[1] >> 1], newhigh[(id[1]>>1)]-1, 1);
		for (i = 2; i <= top; i++)
		{
			ans += (num[i] - num[i-1]) * (len[1] - tot[1]);
			if ((id[i] & 1) == 0) change(newlow[id[i] >> 1], newhigh[(id[i]>>1)]-1, 1);
			else change(newlow[id[i] >> 1], newhigh[(id[i]>>1)]-1, -1);
		}
		printf("Test case #%d\n", test);
		printf("Total explored area: %.2lf\n\n", ans);
	}
	return 0;
}


内容概要:本文详细介绍了一种基于Simulink的表贴式永磁同步电机(SPMSM)有限控制集模型预测电流控制(FCS-MPCC)仿真系统。通过构建PMSM数学模型、坐标变换、MPC控制器、SVPWM调制等模块,实现了对电机定子电流的高精度跟踪控制,具备快速动态响应和低稳态误差的特点。文中提供了完整的仿真建模步骤、关键参数设置、核心MATLAB函数代码及仿真结果分析,涵盖转速、电流、转矩和三相电流波形,验证了MPC控制策略在动态性能、稳态精度和抗负载扰动方面的优越性,并提出了参数自整定、加权代价函数、模型预测转矩控制和弱磁扩速等优化方向。; 适合人群:自动化、电气工程及其相关专业本科生、研究生,以及从事电机控制算法研究与仿真的工程技术人员;具备一定的电机原理、自动控制理论和Simulink仿真基础者更佳; 使用场景及目标:①用于永磁同步电机模型预测控制的教学演示、课程设计或毕业设计项目;②作为电机先进控制算法(如MPC、MPTC)的仿真验证平台;③支撑科研中对控制性能优化(如动态响应、抗干扰能力)的研究需求; 阅读建议:建议读者结合Simulink环境动手搭建模型,深入理解各模块间的信号流向与控制逻辑,重点掌握预测模型构建、代价函数设计与开关状态选择机制,并可通过修改电机参数或控制策略进行拓展实验,以增强实践与创新能力。
<think>我们计划覆盖以下算法类型:数据结构、动态规划、图论、数学、字符串、计算几何、搜索、贪心、分治等。 题目来源包括:洛谷(Luogu)、LeetCode、Codeforces、AtCoder、HDUPOJ等。 我们将按照类型分类,每个类型选取若干经典题目,总数不少于50题。 注意:由于不同OJ的链接格式不同,我们将给出直接可访问的完整链接(部分可能需要用户有账号或平台公开访问)。 由于平台限制,部分国内平台链接可能需要登录,但题目编号和名称足够清晰。 以下是分类题目列表:</think>### 算法竞赛精选题目集(50+题) #### 一、数据结构(12题) 1. **线段树进阶** [P3373 线段树2](https://www.luogu.com.cn/problem/P3373) - 区间乘加混合操作 [CF52C Circular RMQ](https://codeforces.com/problemset/problem/52/C) - 环形区间最值 [P5490 扫描线](https://www.luogu.com.cn/problem/P5490) - 矩形面积并 2. **树状数组** [P3368 树状数组2](https://www.luogu.com.cn/problem/P3368) - 区间修改单点查询 [P3759 逆序对](https://www.luogu.com.cn/problem/P3759) - 带删除逆序对 3. **平衡树** [P3391 文艺平衡树](https://www.luogu.com.cn/problem/P3391) - Splay区间翻转 [P1486 郁闷的出纳员](https://www.luogu.com.cn/problem/P1486) - 带删除的平衡树 4. **分块/莫队** [P4137 Rmq Problem](https://www.luogu.com.cn/problem/P4137) - mex查询 [CF86D Powerful array](https://codeforces.com/problemset/problem/86/D) - 区间幂次和 --- #### 二、动态规划(10题) 1. **树形DP** [P2607 骑士](https://www.luogu.com.cn/problem/P2607) - 基环树DP [CF856C Eleventh Birthday](https://codeforces.com/problemset/problem/856/C) - 数位DP 2. **状态压缩** [P3959 宝藏](https://www.luogu.com.cn/problem/P3959) - 状压+DFS [CF11D A Simple Task](https://codeforces.com/problemset/problem/11/D) - 简单环计数 3. **斜率优化** [P3195 玩具装箱](https://www.luogu.com.cn/problem/P3195) - 经典斜率优化 [CF674C Levels](https://codeforces.com/problemset/problem/674/C) - 期望DP优化 --- #### 三、图论(10题) 1. **网络流** [P2764 最小路径覆盖](https://www.luogu.com.cn/problem/P2764) - DAG最小路径覆盖 [CF1082G Petya and Graph](https://codeforces.com/problemset/problem/1082/G) - 最大权闭合子图 2. **连通性** [P3388 割点](https://www.luogu.com.cn/problem/P3388) - 求割点 [CF123E Maze](https://codeforces.com/problemset/problem/123/E) - 期望路径计数 3. **生成树** [P2619 最小生成树](https://www.luogu.com.cn/problem/P2619) - 带权二分 [CF888G Xor-MST](https://codeforces.com/problemset/problem/888/G) - 异或最小生成树 --- #### 四、数学(8题) 1. **数论** [P3307 项链](https://www.luogu.com.cn/problem/P3307) - Burnside引理 [CF1119F Niyaz and Small Degrees](https://codeforces.com/problemset/problem/1119/F) - 度数限制生成树 2. **组合数学** [P6669 组合数问题](https://www.luogu.com.cn/problem/P6669) - Lucas+数位DP [CF1342E Placing Rooks](https://codeforces.com/problemset/problem/1342/E) - 错排问题 --- #### 五、字符串(5题) 1. **KMP/AC自动机** [P2444 病毒](https://www.luogu.com.cn/problem/P2444) - AC自动机+拓扑 [CF1207G Indie Album](https://codeforces.com/problemset/problem/1207/G) - AC自动机+DFS序 2. **后缀数组** [P2178 品酒大会](https://www.luogu.com.cn/problem/P2178) - 后缀数组+并查集 [CF123D String](https://codeforces.com/problemset/problem/123/D) - 后缀自动机 --- #### 六、计算几何(5题) 1. **凸包/旋转卡壳** [P1452 旋转卡壳](https://www.luogu.com.cn/problem/P1452) - 平面最远点对 [CF1045I Palindrome Pairs](https://codeforces.com/problemset/problem/1045/I) - 回文向量 2. **半平面交** [P3256 半平面交](https://www.luogu.com.cn/problem/P3256) - 凸多边形交 [CF1120C Compress String](https://codeforces.com/problemset/problem/1120/C) - 字符串DP --- #### 七、其他(10题) 1. **分治/CDQ** [P3810 三维偏序](https://www.luogu.com.cn/problem/P3810) - CDQ分治 [CF626F Group Projects](https://codeforces.com/problemset/problem/626/F) - 差值DP 2. **搜索/剪枝** [P1379 八数码](https://www.luogu.com.cn/problem/P1379) - A*搜索 [CF1100E Andrew and Taxi](https://codeforces.com/problemset/problem/1100/E) - 二分+拓扑 3. **交互题** [CF1167F Scalar Queries](https://codeforces.com/problemset/problem/1167/F) - 树状数组应用 [CF1523D Love-Hate](https://codeforces.com/problemset/problem/1523/D) - 随机化 --- ### 训练建议 1. **刷题策略**: ```mermaid pie title 题目类型分配 “数据结构” : 25 “动态规划” : 20 “图论” : 18 “数学” : 15 “其他” : 22 ``` 2. **每日计划**: - 上午:3题(数据结构+DP) - 下午:2题(图论+数学) - 晚上:1题(综合/难题) 3. **必备资源**: - [OI Wiki](https://oi-wiki.org/) 算法百科 - [Codeforces Problemset](https://codeforces.com/problemset) 按rating筛选 - [Luogu 题单广场](https://www.luogu.com.cn/training/list)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值