最近做题小结

https://www.luogu.com.cn/problem/AT_abc373_e

这道题是个二分 然后标答是两个二分 我用的树组+二分
需要对代数式进行拆分才能得到
我一开始看错题目了 看成大于等于他的票的人不多于M就行
然后就很简单 我觉得可以改编下这个题

很明显 最终前m个人一定当选

那么对于每一个人 我们就是尽量求他能不能利用最后的票让自己当选
求这个票的最小值

那我们先进行排序 从小到大排好

对于已经排前M的人来说 我们把他给抹掉 然后让m+1的人变成m位
此时我们对他进行二分判断最小 因为虽然我已经排前m了 但是
票数多太多的情况下 还是会被反超

对于这个抹掉可以写一个change函数 然后 后面再加上去就行

难就难在这个树状树组的写法上

现在分情况讨论 如果我已经前m位了 现在我删掉自己
二分了一个 ans可以进前m位的第2假设m为5 此时 假设多的票数总共是sum
sum-ans要让3 4 5 不可以反超 则有后面的总和加上sum-ans小于等于3*(ans+ai)这样就可以做到了

说白了就是后面的所有票数要小于人数*(ai+ans+1)

不能等于

这种求和用树组是log操作 明显可以做 对于查找位置 可以
内置lowerbound upperbound进行查找

为了查多少名不是通过low upp 因为他们返回的是数值
所以必须开再一开一个树组进行访问

struct Tree{
	int tr[range];
    void modify(int x,int d)
	{
		int dex=lower_bound(num+1,num+1+cnt,x)-num;
		//位置 xx
		for(int i=dex;i<=cnt;i+=i&-i)
		{
			tr[i]+=d;
		}
//		for(int i=dex;i<=cnt;i+=i&-i)
//		{
//			cout<<tr[i]<<" "<<i<<" "<<x<<" "<<dex<<endl;
//		}
	}
     int  query(int x)
	{
		int res=0;
		int dex=upper_bound(num+1,num+1+cnt,x)-num-1;
//		cout<<dex;
//		for(int i=dex;i>=0;i-=i&-i)
		for(int i=dex;i;i-=i&-i)
		{
		res+=tr[i];
		}	
//		cout<<"res:"<<res<<endl;
		return res;
	}	
}t1,t2;

挺不容易的

考虑建树 只需要 枚举前m位


	k=k-sum;
	sort(num+1,num+1+cnt);
	cnt=unique(num+1,num+1+cnt)-num-1;
	sort(a+1,a+1+n,cmp);
//离散 
	for(int i=1;i<=m;i++)
	{
		t1.modify(a[i].x,a[i].x);
		t2.modify(a[i].x,1);
	}

后面删除:

if(i<=m)
		{
	    t1.modify(a[i].x,-a[i].x);
        t2.modify(a[i].x,-1);
		t1.modify(a[m+1].x,a[m+1].x);
		t2.modify(a[m+1].x,1);	
		}		

这题就这样了 难!

https://www.luogu.com.cn/problem/AT_abc372_d

这题是一个栈的题目 对于栈 我使用的很不好
网络赛考的栈 我没想出 只好想了更麻烦的做法 虽然时间更优秀
简要思路

倒着循环 我们能每访问一个点 就不断弹出stack 直到 一个比他大的值出现 则就是答案

https://www.luogu.com.cn/problem/AT_abc372_e
题目
连接u-v 查u联通下标第k大的点

启发式合并题
观察数据范围 其实k只有10大 那我么每次维护 连接边的时候都可以sort下
那么和启发式合并有什么关系呢 我们每次将小的放大的 最终就是
log步就能放满所有了

为什么合并呢 反正都能互相到达 所有合并了肯定是可以的

每次只保留k个就行

合并 
	for(auto i:e[two]){
		e[one].push_back(i);
	}
int  find1(int i)
{
	if(i==fa[i])return i;
	else 
	{//下面这一步可不能省略 不然不能体现路径压缩
		fa[i]=find1(fa[i]);
		return fa[i];		
	}
}
void merge(int u,int v)
{
	int one=find1(u);
	int two=find1(v);
	if(one==two)return ;
	for(auto i:e[two]){
		e[one].push_back(i);
	}
	sort(e[one].begin(),e[one].end(),greater<int>());
	while(e[one].size()>10)e[one].pop_back();
	fa[two]=one;
}
void solve()
{
	
	cin>>n>>q;
	for(int i=1;i<=n;i++)e[i].push_back(i);
	for(int i=1;i<=n;i++)fa[i]=i;
	while(q--)
	{
		int op,u,v;
		cin>>op>>u>>v;
		if(op==1){
			merge(u,v);	
		}
		else {
		  int w=find1(u);
			if(e[w].size()<v)cout<<-1<<endl;
			else 
			cout<<e[w][v-1]<<endl;
		}
	}

https://www.luogu.com.cn/problem/AT_abc329_f

这题给我很大的其实就是sets[range]可以这么搞
以前都不知道

那么就是一个简单的启发式合并了

非常good的一道题

	while(m--)
	{
		int a,b;
		cin>>a>>b;
//		int a=find1(u);
//		int b=find1(v);
		//不需要unoin 就不用find 
		if(s[a].size()<s[b].size()){
//			swap(s[a].size(),s[b].size());
		for(auto i:s[a])s[b].insert(i);
			s[a].clear();
			cout<<s[b].size()<<endl;
		}
		else {
			swap(s[a],s[b]);
			for(auto i:s[a])s[b].insert(i);
			s[a].clear();	
			cout<<s[b].size()<<endl;
		}
		//也可以直接swap s[a] s[b]
	}
posted @   想念不动声色  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示