22.3.5


小记,关了同步的cin基本上可以当scanf用了,并且耗时上真的相差无几,验证过了

 

上面两次是scanf,下面全是cin,输入数据是1e5;


 

1,合并集合

对find函数(递归)的深入理解

首先,初始化一下    p[1]=1,p[2]=1,p[3]=2,p[4]=3,p[5]=4;所以我们明白这些都是是以1为祖宗结点的集合

递归的运行过程就明白的显示了出来;

find(5)→find(p[5])→find(p[p[5]])→find( p[p[p[5]]])→find(p[p[p[p[5]]]]);

find(5)→find(  4  )→find(    3   )→find(       2      )→fin(1);

并且find(4)一样,这是没有进行路径压缩,那么路径压缩是咋样的呢,只需一步,

在find函数里,加上p[x] = find(p[x]);

 如图所示,完成路径压缩的优化后,find(4)是一步到位;基本上可以看作插入和查询都是在O(1)内完成的;

2,小朋友的数字

特征值的求法,是连续的区间最大和!不是只取正值,积累起来的和!!;

可以dp求特征值,也可以维护一可更新的最大值;

关键是:能够发现特征值是单调递增的!!它总是tt[i] >= tt[i-1];

根据这个,在求分数的时候,可以贪心来做;贪心的思想就是tt[i-1]<0,那么最大分数值只能是fs[2],只要tt[i-1]>0,就可以fs[i]= fs[i-1] + tt[i-1] ;

所以其实分数也是具有单调性的;

最后注意分数 会爆longlong,大于1e9就取余;


一直取余也可以过。。

然后对特征值整体取余也可以过,。。。,为啥??


#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++)
#define rep2(i,a,n) for(int i=a;i<=n;i++)
#define per1(i,n,a) for(int i=n;i>a;i--)
#define per2(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
using ll=long long ;
using PII=pair<int,int>;
void quick_cin()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
}
const int N=1e6+10;
ll tt[N];
ll fs[N];
int n,p;
bool flag;
int main()
{	
	quick_cin();
	cin>>n>>p;
	ll sum=0,maxsum=0;
	rep2(i,1,n)
	{
		int x;cin>>x;
		if(i==1)tt[1]=sum=maxsum=x;
		else
		{
			if(sum<0)sum=0;
			sum+=x;
			tt[i]=maxsum=max(maxsum,sum);
		}	
	}
	fs[1]=tt[1];
	fs[2]=fs[1]+tt[1];
	rep2(i,3,n)
	{
		if(tt[i-1]>0)
		{
			fs[i]=fs[i-1]+tt[i-1];
			if(fs[i]>fs[1])flag=1;
			if(fs[i]>1e9)fs[i]%=p;		
		}
		else fs[i]=fs[2];
	}
	if(flag)printf("%lld",fs[n]%p);
	else printf("%lld",fs[1]%p);
    return 0;
}

3,连通块中点的数量

和并查集类似,多了一个储存大小的size变量;

细节地方就是一个特判,find(a) == find(b) 的时候,不需要操作,continue掉就行;

#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++)
#define rep2(i,a,n) for(int i=a;i<=n;i++)
#define per1(i,n,a) for(int i=n;i>a;i--)
#define per2(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
using ll=long long ;
using PII=pair<int,int>;
void quick_cin()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
}
const int N=1e5+10;
int p[N],s[N];
int find(int x)
{
	if(p[x]!=x)p[x]=find(p[x]);
	return p[x];
}
int n,m;
int main()
{	
	quick_cin();
	cin>>n>>m;
	rep2(i,1,n)p[i]=i,s[i]=1;
	rep2(i,1,m)
	{
		char x[5];cin>>x;
		if(x[0]=='C')
		{
			int a,b;
			cin>>a>>b;
			if(find(a)==find(b))continue;
			s[find(b)]+=s[find(a)];
			p[find(a)]=find(b);
		}
		else if(x[1]=='1')
		{
			int a,b;
			cin>>a>>b;
			if(find(a)==find(b))printf("Yes\n");
			else printf("No\n");
		}
		else
		{
			int a;
			cin>>a;
			printf("%d\n",s[find(a)]);
		}
	}
    return 0;
}

 4,食物链

读题问题,食物链是个环形!!,就算没说3吃1,只要1吃2,2吃3 是真的,那么环形链接过来,1就是3的食物,3吃1就是真的;

5,模拟堆

手写实现堆:

堆的存储 和完全二叉树类似,都可以用一维数组来存储,但是下标一定从1开始,利用二叉树的性质,左儿子2x,右儿子2x+1,

堆的5个操作及实现,heap表示堆,size表示堆的大小,当然heap[size]就是堆的最后一个元素;

 1:在最后插入一个元素,然后up上去就可;

3:3步曲:①最后的值替换掉最小值;②size--,最后一个元素上去了,当然size--③down(1);最后一个元素上去了,就down它,down到合适的位置;

4,5类似,着重理解down(k) ; up(k) 因为在中间操作一个元素后,它可能朝上也可能朝下;但我不去管他,我直接 down它,up它,该怎么走交给系统;

难点在于操作第k个插入的数,而不是操作第k个数;

第k个插入的数,需要一种映射关系,

开个ph,hp数组,ph存第k个插入的数 的下标,hp存第k个插入的数在ph中的下标,只有

hp[k]=ph[k],两者互相指向对方,就找对了;

#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++)
#define rep2(i,a,n) for(int i=a;i<=n;i++)
#define per1(i,n,a) for(int i=n;i>a;i--)
#define per2(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
using ll=long long ;
using PII=pair<int,int>;
void quick_cin()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
}
const int N=1e5+10;
int n,m,h[N],hp[N],ph[N],cnt;
void heap_swap(int a, int b)
{
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
}

void down(int u)
{
    int t = u;
    if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
        heap_swap(u, t);
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u] < h[u / 2])
    {
        heap_swap(u, u / 2);
        u >>= 1;
    }
}
int main()
{	
	quick_cin();
	cin>>n;
   while (n -- )
    {
        char op[5];
        int k, x;
       	cin>>op;
        if (!strcmp(op, "I"))
        {
            cin>>x;
            cnt ++ ;
            m ++ ;
            ph[m] = cnt, hp[cnt] = m;
            h[cnt] = x;
            up(cnt);
        }
        else if (!strcmp(op, "PM")) printf("%d\n", h[1]);
        else if (!strcmp(op, "DM"))
        {
            heap_swap(1, cnt);
            cnt -- ;
            down(1);
        }
        else if (!strcmp(op, "D"))
        {
            cin>>k;
            k = ph[k];
            heap_swap(k, cnt);
            cnt -- ;
            up(k);
            down(k);
        }
        else
        {
			cin>>k>>x;
            k = ph[k];
            h[k] = x;
            up(k);
            down(k);
        }
    }
    return 0;
}

这里用到了字符串的函数,strcmp,它是比较两个字符串是否相等,相等则为0; 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dull丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值