最近做题小结
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
这题给我很大的其实就是set
以前都不知道
那么就是一个简单的启发式合并了
非常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]
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话