acm_数据结构
文章平均质量分 71
ascii991
这个作者很懒,什么都没留下…
展开
-
poj 1389 线段树+扫描线 求矩形交的面积
【题意】 求矩形交的面积 【题解】 相较之下,比求矩形交的周长简单不少。 维护这样几个量: cov:线段被覆盖几次 sum:线段被覆盖的总长 【教训】 一开始想整段更新一定要用延迟标记,后来发现根本不用。 【代码】 #include #include using namespace std; const int maxl=50000,maxn=1000; struct原创 2012-04-25 10:06:09 · 1492 阅读 · 0 评论 -
APIO2007 数据备份 贪心+堆实现
【算法分析】 n,k都有10^5,所以考虑贪心算法 最基本的贪心就是任意一对数必须是相邻的,这是显然的。 考虑到一重要结论: 假设现在有三条相邻的线段a1,a2,a3;a1>a2,a3>a2,如果a2小于等于最优解集中的最大元素,并且最优解集中不存在a2,则必同时存在a1,a3。 证明:如果最优解中只有a1或只有a3,那我可以把它换成a2,这组解仍然满足要求,但总距离更小。如原创 2012-08-04 13:59:13 · 1295 阅读 · 0 评论 -
线段树典型例题--poj2482
【题意】 Assume the sky is a flat plane. All the stars lie on it with a location (x, y). for each star, there is a grade ranging from 1 to 100, representing its brightness, where 100 is the brightest and原创 2012-07-23 17:04:10 · 652 阅读 · 0 评论 -
线段树典型例题--poj2528
此题的关键在于离散化。 对于线段(a,b),要将a-1,a,b三个量都考虑进去。 否则我们看这样一个例子: 3 1 10 1 3 6 10 答案是3 如果不考虑a-1,则答案会变成2。 【代码】 #include #include #include #include #include using namespace std; const int N=1000原创 2012-07-23 17:09:06 · 486 阅读 · 0 评论 -
线段树典型例题--poj2828
逆序处理。 注意到如果逆序插入,则每次插入的位置都是第x个空位。 所以可以用线段树来寻找第x个合法位置 【代码】 #include #include #include #include #include using namespace std; const int N=200005; int sum[N*3],pos[N],val[N],p[N]; int n; void原创 2012-07-23 17:11:57 · 450 阅读 · 0 评论 -
线段树典型例题--poj3667 hotel
题目很像内存分配。 线段树维护这样几个量: col:节点的颜色(0--没有覆盖,1--全覆盖,-1--有多种颜色) dl:从左边开始的最长连续段 dr:从右边开始的最长连续段 dm:节点中的最长连续段 dp:节点中最长连续段的开始位置 具体见代码: #include #include #include #include #include using namespace s原创 2012-07-23 17:22:37 · 608 阅读 · 0 评论 -
线段树典型例题--poj3277
将x轴上的点离散化。 y轴建立线段树。使用延迟标记。 注意:延迟标记不是单纯覆盖,而是需要比较的。 pp[i]为标记 则应当是pp[i*2]=max(pp[i*2],pp[i]); pp[i*2+1]=max(pp[i*2+1],pp[i]);而不是 pp[i*2]=pp[i*2+1]=pp[i]; 【代码】 #include #include #include #incl原创 2012-07-23 17:16:35 · 548 阅读 · 0 评论 -
线段树典型例题--poj2777
这到题我认为网上有些人的算法是不对的。 void solve(int l,int r,int root) //询问 { if(tree[root].col>=0) //如果父节点有单一的颜色,就直接更新,不需要找到子节点更新 { flag[tree[root].col]=1;//统计哪些颜色出现过 return; } if(t原创 2012-07-23 17:37:27 · 802 阅读 · 0 评论 -
并查集练习---poj 1182 食物链
经典的并查集题目。 主要是节点之间的关系的维护。 首先看路径压缩部分: int find(int x) { if (fa[x]==x) return x; int t=fa[x]; fa[x]=find(fa[x]); r[x]=(r[x]+r[t])%3; return fa[x]; }这里要注意保存原来的父节点。 再看如何合并: fx=find原创 2012-07-28 14:15:52 · 545 阅读 · 0 评论 -
并查集练习---poj 2912
集合的合并与维护和食物链那道题一样。 不过多了个裁判。注意到N 如果有矛盾,则这个人不是裁判。 唯一有点难度的是输出第几行判断出的裁判。 原先以为是最后出现裁判的那一行。 后来发现应当时枚举其他人时候首次出现矛盾的最大值。(仔细想想) 这样这道题就解决了。 【代码】 #include #include #include #include #include using原创 2012-07-28 14:37:09 · 535 阅读 · 0 评论 -
并查集练习---poj 1984
usaco的月赛题。 记录两个点之间x方向和y方向的相对距离,用并查集维护。 若与poj 1182食物链进行比较,便会发现路径压缩部分,集合合并部分的相似点。 所以并查集不难,是有一定套路可循的。大家一定要好好总结。 【代码】 #include #include #include #include #include using namespace std; const i原创 2012-07-28 14:20:21 · 1590 阅读 · 0 评论 -
poj 1204 AC自动机
AC自动机的经典题 可以使用一个小技巧,将要查找的单词反过来建自动机,这样便于记录首字母的位置。 #include using namespace std; const int maxn=1005,maxl=200000; const int dx[9]={0,-1,-1,0,1,1,1,0,-1}; const int dy[9]={0,0,1,1,1,0,-1,-1,-1}; str原创 2012-04-13 16:34:47 · 393 阅读 · 0 评论 -
poj 1635 判断树是否同构
【题意】 给出两棵树,判断树是否同构。 树的表示:从根节点深搜,0表示向下,1表示向上回溯,得到的01串。 【题解】 将树最小表示,排序 如何得到子树:子树的01串中0和1的数量相等。 所以只需递归求解。 【代码】 #include #include #include #include using namespace std; const int maxn=3005;原创 2012-04-26 17:41:19 · 2211 阅读 · 0 评论 -
poj 1177 线段树+扫描线 求矩形交的周长
【题意】 给定n个矩形,求他们的交的周长。 【题解】 以Y轴建立线段树,X轴为扫描方向。 线段树维护这样几个量: cov:表示线段被覆盖几次 num:该线段有几个被覆盖的区间段 sum:该线段被覆盖的总长度 lcover,rcover:线段左右两边是否被覆盖。 对于竖边,看每次插入线段时sum[1]的增量。 对于横边,看被覆盖的区间段数。 【教训】 一开始计算竖边是不是原创 2012-04-25 09:58:54 · 761 阅读 · 0 评论 -
poj 2274 线段树+堆
这道题可以说是数据结构题当中的一道综合题。 【题意】 给定n辆车的坐标xi,速度vi,求会发生超车事件的数量(求逆序数对),并按时间顺序输出超车事件的车对。 【题解】 第一问,经典的线段树求逆序数对,nlogn水过 第二问,比较繁。对于超车,首先必须明确一点:只有相邻的两辆车才会可能较早的发生超车。即对于三元组(i,j,k),若i能超过k,j也能超过k,则在i超过k之前,i要么超过了j,原创 2012-04-14 19:49:17 · 1520 阅读 · 0 评论 -
poj 3415 后缀数组+栈优化
【题意】 统计两个串中长度>=k的公共子串的数量。 【题解】 很容易想到将两个串连接起来,求后缀数组,在根据k分组 但统计是件麻烦事。。。 以下是我自己搞出来的方法: 搞一个单调的栈维护lcp,然后维护单调性。 统计的时候要注意,只有不同的串的lcp才能统计。 这个方法严格的来说不能算是O(n),但是很接近。 结合代码分析: long long work() {原创 2012-05-04 16:19:06 · 1242 阅读 · 0 评论 -
poj 3294 后缀数组
【题意】 给定N个串,求最长的子串S,使得S为其中超过一半的串的公共子串。 【题解】 后缀数组,按height数组分组,按sa数组输出。 【代码】 #include #include #include using namespace std; const int maxn=200000; int s[maxn],w[maxn],wa[maxn],wb[maxn],x[maxn原创 2012-04-20 14:28:43 · 585 阅读 · 0 评论 -
poj 2778 AC自动机DP
从AC了poj1625 censored!一题后,又解决了一道AC自动机DP题。 【题意】 同poj 1625 【题解】 poj 1625是dp,而这道题的DP通过矩阵实现。 【代码】 #include #include using namespace std; const int maxn=100,base=100000,kind=4; struct node {原创 2012-05-02 15:05:28 · 662 阅读 · 0 评论 -
poj 1625 AC自动机上的DP
好题!搞了N久终于AC! 【题意】 给定N个字符集合和P个禁用的字符串,求长度为M的合法字符串个数。 【题解】 显然是AC自动机上的DP。 令dp[i][j]表示长度为i,状态为j的字符串个数。 按自动机的图转移即可,但要注意细节。 贡献几组数据。 50 50 10 qwertyuiop[]\asdfghjkl;'zxcvbnm,./ QWERTYUIOP{}|A原创 2012-04-15 11:25:03 · 1642 阅读 · 0 评论 -
poj 2010 二叉堆
数据结构题 【题意】 给定C个牛的CSAT分数score[i],和需要的资费aid[i],求上述C头牛的一个N元子集,使得其中位数最大,而资费总和 【题解】 先按照score[i]排序,再枚举i,现在的任务就是求: i前面哪n/2头牛的资费和最小; i后面哪n/2头牛的资费和最小; 建大根堆维护即可。 【教训】 我一开始想在线算法,即一次将上述两问求出,后来发现这样做就繁了,可以原创 2012-04-15 11:13:22 · 790 阅读 · 0 评论 -
poj 3623 贪心,后缀数组
【题意】 给你一个字符串,现在要生成一个新的字符串,规则是每次从原字符串的头部或者尾部取一个字符放在新字符串的尾巴上。求字典序最小的新字符串。 【题解】 简单贪心,用后缀数组即可。 贡献了两个presantation error T_T 【代码】 #include using namespace std; const int maxn=60010; int wa[maxn]原创 2012-05-06 15:28:28 · 671 阅读 · 0 评论 -
poj 1988 并查集
【题意】 有几个stack,初始里面有一个cube。支持两种操作:1.move x y: 将x所在的stack移动到y所在stack的顶部。2.count x:数在x所在stack中,在x之下的cube的个数。 【题解】 并查集。与银河英雄传说类似。 维护两个量s[x]和d[x],表示子树大小和到根的距离。 详情看代码: #include using namespace st原创 2012-05-05 09:46:52 · 2358 阅读 · 2 评论 -
后缀数组小结--poj2406,poj3693,poj2774,poj1743
自己搞OI的时候没学(惭愧,都冲进NOI了居然还不会后缀数组!),现在搞ACM了,就学了学人家的论文,做了几题,小结一下。 感觉这些题有些模块比较重要: 首先是求后缀数组: int cmp(int *r,int a,int b,int l) { return r[a]==r[b] && r[a+l]==r[b+l]; } void da(char *s,int *sa,int n原创 2012-04-11 10:44:55 · 2621 阅读 · 0 评论 -
并查集练习---poj 1417 并查集+DP
这到题倒是和team them up 有些类似。 很容易得到:回答yes ,则x和y是相同集合的,反之,则是不同集合的。 首先用friend-enemy 并查集,注意:不要将朋友和敌人分开维护,这样容易出错。 得到了若干集合,每个集合有两个数,a和b。 现在要求n个集合中各挑出一个数(a或者b),使得他们之和等于p1(说真话的人数)。而这个用dp可以很好的解决,用f[i][j]表示原创 2012-07-28 14:28:57 · 1409 阅读 · 0 评论