ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021/7/6——集训Day.1

2021-07-06 21:30:56  阅读:229  来源: 互联网

标签:Day.1 区间 dfs ST int 2021 fh 集训 st1


昨天晚上还是正常失眠,跟隔壁寝室商量了卫生间值日是一个寝室一天,以男人的决斗方式我险胜,他们先。寝室只有四个人,以男人的决斗方式我输了,沦为了寝室长,自闭,早上我去洗漱还没人起床,我值过日还有两人每走,sr大佬还好心帮我把他们踩脏的地方拖干净了,针不戳。早上由于hyp回去拿了个东西,我和sr在外面等的时候还被围观了,梨谱 … … …… ……而我自己还忘了带水杯,只能买了瓶框钱水。
早上过来就直接跟榜,开始写一道并查集的题:给出一个长度为 100000 100000 100000 的序列,每个数字不超过 1 0 9 10^9 109 ,再给每个时间摧毁序列中第几个数,然后输出 n n n 次,每次输出没有被摧毁的数组成的最大的连续子序列。

#include<bits/stdc++.h>
using namespace std;
#define N 100010
bool flag[N];long long ans[N],fa[N],sz[N],maxx;int n,fh,a[N],t[N];
int get_father(int x)
{
	if(x==fa[x])return x;
	return fa[x]=get_father(fa[x]);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){scanf("%d",&a[i]);fa[i]=i;}
	for(int i=1;i<=n;i++){scanf("%d",&t[i]);}
	for(int i=n;i>1;i--)
	{
		fh=t[i];flag[fh]=1;//复活
		if(flag[fh-1]==1){sz[fh]+=sz[get_father(fh-1)];fa[get_father(fh-1)]=fh;}
		if(flag[fh+1]==1){sz[fh]+=sz[get_father(fh+1)];fa[get_father(fh+1)]=fh;}
		sz[fh]+=a[fh];maxx=max(maxx,sz[fh]);ans[i]=maxx;
	}
	for(int i=2;i<=n;i++)printf("%lld\n",ans[i]);printf("0");
	return 0;
}

解:倒着做,不要从一开始把序列中的数毁掉,而是把数一个一个复活,然后并查集维护。
早上写出来了,但是有一个小细节没搞好,然后课间改了出来。


上午是jjh金牌学长讲课,讲的是一些数据结构,并查集 + + + 树状数组 + + + S T ST ST 表 + + + 线段树,涉及到些目前我认为的比较高级的操作。
感觉算是听懂了大半吧,不能说完全明白,但是绝对受益匪浅。
比方说zkw线段树,摒弃了传统线段树的从根到叶,zkw线段树是从叶子到根,但是有些传统线段树的操作在zkw线段树中是难以实现的。感觉实用程度不如我的学长zyz发明的zyz线段树。
还有并查集中的 K r u s k a l Kruskal Kruskal 重构树,感觉好高级,用法和道理都懂,就是不会码。
最梨谱的是最后讲的“历史最小值”,直接去世。
S T ST ST 表我还是不会自己手写 … … …… ……自闭了,辛亏不是今天的重点内容,不然就亏大发了。
说起来课间还嫖了jjh学长带的《纪念品》——来自清华大学的小书签和胶带。
中午为了不被卷死,就留在了机房不敢回寝室,真自闭啊,吃饭的时候还因为头晕没站稳把汤撒到桌子上很多,差点溅到lyn大佬的外套上!
但是中午刚回来就吃了好多jjh学长和他女朋友的狗粮,太自闭了,根本学不进去啊!!!(还好jjh学长一会儿就睡着了,然后我就开始写博客总结)
但说起来还是hyp大佬强啊(给hyp大佬的真实姓名和头像手动打码)
在这里插入图片描述
等到午休时间结束,zwj老师说要在发的《学员证》上写名字,然后由于我昨天不小心洗脸把里面的卡片弄湿了没管,想掏出来写名字的时候纸断在了里面,太自闭了。


总结下具体的知识点吧:
首先是启发式合并

如果有两个并查集块要合并,对于每个节点维护出子树的大小,然后让小的成为大的的儿子,可以把查询根节点的复杂度降低为为 O(log n),这是数据结构,所以具体我就不证明了,以知道+会用为主。

还有就是路径压缩

将所有孩子的父亲直接连到祖先身上,最优情况下树可以变成菊花图,而在一般数据范围下查询连通性时时间复杂度应该是一个3~4的小常数(jjh学长是这样讲的,我以前一直以为是O(1)的)

然后是 K r u s k a l Kruskal Kruskal 重构树,以权值从小到大或从大到小连出一个并查集,由于并查集主要是针对集合,所以这样做也没有太大关系。当时课上给的例题是:

给n个点,m个有权值的边,然后每次询问时给出一个a值,从x点开始,一开始长度小于a的边可以直接跳过,然后求出跑到1号节点所经过的路程的长度。

P4768 [NOI2018] 归程
题意大概就是这样,我当时理解的这就跟飞行棋一样——一开始掷骰子没小于 4 4 4 的话不能出家门,等出了家门就可以随便搞了。
然后一开始就无从下手。正解大概就是先跑个 D i j k s t r a Dijkstra Dijkstra ,然后用 K r u s k a l Kruskal Kruskal 重构树维护,这样就可以直接跳过权值小于 a a a 的边了,再用倍增优化。(口胡出来大概就是这样了吧,但是对于 K r u s k a l Kruskal Kruskal 重构树的代码和倍增的细节还是不太清楚,大概就是直接加上点权大于 a a a 的限制在树上倍增即可),代码部分先跳过 … … …… ……
树状数组中包含了我昨天写的那个例题,但是被一笔改过了。主要还是我太菜,昨天写了那么长的时间才搞出来,真乾啊!

再往下就是 S T ST ST 表

只能询问不能修改,这个算法如果想要活下来,询问的复杂度必然是极低的。 O(n log n) 的时间内足够完成 ST 表的构造。而对于查询最大值一类的问题,可以拆成几个子区间,单次查询复杂度为O(1)。在求 LCA 的问题中,可以不用树链剖分或者倍增,而是用 ST 表+欧拉序(跟dfs序相似,我大概说下吧)进行复杂度为O(1)的查询,就很神奇。

对于一个树在这里插入图片描述
我们左儿子优先 d f s dfs dfs 序为 1    2    3    4    5 1\; 2\; 3 \;4 \;5 12345
而欧拉序为 1    2    3    2    4    2    1    5    1 1 \;2 \;3 \;2 \;4 \;2 \;1 \;5 \;1 123242151(大概就是这样子,不管是从上到下还是从下到上的时候,只要是经过了就让它进去)
zyz学长给了个求欧拉序的代码(出于对版权的尊重,码风我就不改了)

void dfs(int x,int F)
{
	stb[id[x]=++dfs_clock][0]=x;
	Graph(x){
		if(y==F)continue;
		dep[y]=dep[x]+1;
		dfs(y,x);
		stb[++dfs_clock][0]=x;
	}
}

具体咋实现我也不会,上午全程就光听学长口胡了,太细的地方还要自己抠抠才好
再往下是线段树区间修改区间查询之类的东西,懒标记我还是会下的。
zkw线段树

emmmm……感觉应用前景不是很广泛,前文也说过是做什么用的,我没太学会,有这功夫还不如想想zyz线段树,zyz学长yyds!!!(破音)

线段树求对于一个区间的最大子区间和:

维护每个区间的最大子区间和,从左端点出发的最大子区间,从右端点出发的最大子区间,这是很容易理解的,当两个区间合并时,我们在左区间的最大子区间,右区间的最大子区间,和两区间中间连着的部分(分别为靠近另一区间为端点的最大子区间的和),三者中取max即为该区间的最大子区间,然后以此类推往上传递

历史最小值问题:

没太听懂


然后翻译了个题面,开始码代码。
突然又过来统一解答了些上午存在的问题,历史最小值还是不懂,太自闭了。
第一个题

给出n-1个有向边,由儿子指向父亲,q次操作,可能是把某一点标记,也可能是询问某一点的最近被标记祖先(一个点本身也算是自己的祖先)

P4092 [HEOI2016/TJOI2016]树
自闭了,本来应该是个并查集的题,但是他们都是用的 d f s dfs dfs 水过去的,我当然不能搞特殊!
练成无向边,然后 d f s dfs dfs 遍历,给每个点都标记,如果删标记把一个点上的标记删完,就合并,总之很神奇,洛谷上也 A A A 掉了。(一开始邻接表没开二倍错了一发)

#include<bits/stdc++.h>
using namespace std;
#define N 100010
struct eo{int y,nxt;}e[N<<1];
int f[N],shen[N],q,n,tot,a,hd[N],b;char flag[2];
void lian(int x,int y){e[++tot].y=y;e[tot].nxt=hd[x];hd[x]=tot;}
void dfs(int x,int y)
{
	for(int i=hd[x];i;i=e[i].nxt)
	{
		if(e[i].y==y)continue;
		shen[e[i].y]=shen[x]+1;dfs(e[i].y,x);
	} 
}
void xiugai(int x,int y)
{
	for(int i=hd[x];i;i=e[i].nxt)
	{
		if(shen[e[i].y]<shen[x])continue;
		if(shen[f[e[i].y]]<shen[f[x]]){f[e[i].y]=f[x];xiugai(e[i].y,x);}
	}
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<n;i++){f[i]=1;scanf("%d%d",&a,&b);lian(a,b),lian(b,a);}
	shen[1]=1;dfs(1,0);f[n]=1;
	while(q--)
	{
		scanf("%s%d",flag,&a);
		if(flag[0]=='C'){f[a]=a;xiugai(a,a);}
		else printf("%d\n",f[a]);
	}
	return 0;
}

然后把一个之前写过的题粘到集训的临时 o j oj oj 中提交,啧啧啧
然后开始看[HAOI2015]树上操作
然后看到吃饭也不想码代码,吃饭的时候myf大佬说这是树链剖分,所以我又不想写了
开始看P2048 [NOI2010] 超级钢琴,并且现学 S T ST ST 表

ST算法利用倍增的思想,在O(N logN)的复杂度下进行预处理,然后通过O(1)的复杂度就可以查询到任意区间中的最大值,以倍增的方式找到一个长度lenth,使得lenth>=(l+r)/2,感觉就跟线段树差不了多少啊,只不过可能会覆盖同一小块儿区间多次而已啊。不过板子差的还挺多的,而且不能修改……

还在看书的时候发现自己被机惨了
然后运用了电脑自带的画图反%%%回去
在这里插入图片描述
然后上个厕所呼吸下新鲜空气继续学习
看了看晋文公世子jsy大佬的代码,有个很酷的操作(我一开始没注意到树上有,问了才知道):

bool operator <(const node &x,const node &y)
{
	return sum[x.t]-sum[x.s-1]<sum[y.t]-sum[y.s-1];
}

原来是结构体的堆 … … …… ……太神奇了,然后就看着jsy的代码和《算阶》写完了

#include<bits/stdc++.h>
using namespace std;
#define N 500010
int f[N][23],n,k,zuo,you,a;
long long qzh[N],ans;
struct node{int s,l,r,t;}st1,st2;
bool operator <(const node &x,const node &y){return qzh[x.t]-qzh[x.s-1]<qzh[y.t]-qzh[y.s-1];}
priority_queue<node> q;
void ycl()
{
	for(int i=1;i<=n;i++)f[i][0]=i;
	int t=log(n)/log(2)+1;
	for(int j=1;j<t;j++)for(int i=1;i<=n-(1<<j)+1;i++)
	{
		if(qzh[f[i][j-1]]>qzh[f[i+(1<<(j-1))][j-1]])f[i][j]=f[i][j-1];
		else f[i][j]=f[i+(1<<(j-1))][j-1];
	}
}
int xw(int l,int r)
{
	int k=log(r-l+1)/log(2);
	if(qzh[f[l][k]]>qzh[f[r-(1<<k)+1][k]])return f[l][k];
	return f[r-(1<<k)+1][k];
//	return max(f[r-(1<<k)+1][k],f[l][k]);
}
int main()
{
	scanf("%d%d%d%d",&n,&k,&zuo,&you);
	for(int i=1;i<=n;i++){scanf("%d",&a);qzh[i]=qzh[i-1]+a;}
	ycl();
	for(int i=1;i<=n-zuo+1;i++)
	{
		st1.s=i;st1.l=i+zuo-1;st1.r=min(i+you-1,n);
		st1.t=xw(st1.l,st1.r);q.push(st1);
	}
	while(k--)
	{
		st1=q.top();q.pop();
		ans=ans+qzh[st1.t]-qzh[st1.s-1];st2.s=st1.s;
		if(st1.l!=st1.t)
		{
			st2.t=xw(st1.l,st1.t-1);
			st2.l=st1.l;st2.r=st1.t-1;q.push(st2);
		} 
		if(st1.r!=st1.t)
		{
			st2.t=xw(st1.t+1,st1.r);
			st2.l=st1.t+1;st2.r=st1.r;q.push(st2);
		}
	}
	printf("%lld",ans);
	return 0;
 } 

用堆维护一个四元组(四元组是啥?我也不懂,反正jjh学长是这样写的,我看就是个结构体),然后取出结构体的时候就再拆拆,得到 S T ST ST 表再放进去。半懂不懂吧,真难啊,嘤。
在这里插入图片描述
《 我 与 出 题 人 》 《我与出题人》 《我与出题人》
然后开始复习树链剖分,之所以把“复习”打成斜体是因为我一开始就妹有学会,太离谱了。对于[HAOI2015]树上操作这个题,其实原来老师布置的作业里有,当时我就不会写,真自闭啊 … … …… ……

《算阶》上没有找到,看别人博客大概就是:找重边?然后剖出来链处理?(不要看这一句话,会误人子弟的)。最后也没搞明白,然后差不多该回寝室了,就这样草草结束吧,等明天老师讲

标签:Day.1,区间,dfs,ST,int,2021,fh,集训,st1
来源: https://blog.csdn.net/ydsrwex/article/details/118509706

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有