其实也是近一个月之前的一场cf了,div3真是吼啊。今天忽然想起来补完剩下的题。

前五道暴力模拟什么的略过不写了。

E2 Array and Segments (Hard version)

题意:给出大小为n的数组a,m个区间。你可以决定每个区间是否进行操作(对区间内的数全部减1),给出任一方案使得数组最大值与最小值的差最大。n<=1e5,m<=300

E2和E1的区别只有数据范围,E1可以暴力枚举选择每个数作为最小值的情况(将包含最小值的区间全部进行操作),每次更新答案,O(n2m)。

E2可以在此基础上进行改进。线段树进行区间操作查询最大值的优化比较好想。然后发现这个m很小…从m入手发现可以用所有区间的端点可以将数组分成不超过601段,在每一段内的i我们按照如上原则选择的操作是相同的,由此可以批量处理降低时间复杂度。

(然而代码写的就非常不优雅,我自己看完都想说这是什么辣鸡…甚至一年半没写线段树了吧。有机会可能会看看官方Tutorial里的方法重写。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define Max(a,b) (a>b?a:b)
#define N 100005
#define INF 0x3f3f3f3f
using namespace std;
int read()
{int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,a[N],l[303],r[303];
int seg[606],ans=0;
vector<int>A,cp;
struct Node
{int l,r,maxn,lazy;
}t[N*4];
void build(int idx,int l,int r)
{t[idx].l=l,t[idx].r=r;if(l==r){t[idx].maxn=a[l],t[idx].lazy=0;return;}int mid=(l+r)>>1;build(idx<<1,l,mid),build(idx<<1|1,mid+1,r);t[idx].maxn=Max(t[idx<<1].maxn,t[idx<<1|1].maxn);
}
void pushdown(int idx)
{if(t[idx].lazy&&t[idx].l!=t[idx].r){int lz=t[idx].lazy;t[idx].lazy=0;t[idx<<1].lazy+=lz,t[idx<<1|1].lazy+=lz;t[idx<<1].maxn+=lz,t[idx<<1|1].maxn+=lz;}
}
void add(int idx,int l,int r,int w)
{if(l<=t[idx].l&&r>=t[idx].r){t[idx].maxn+=w,t[idx].lazy+=w;return;}pushdown(idx);int mid=(t[idx].l+t[idx].r)>>1;if(r<=mid)add(idx<<1,l,r,w);else if(l>mid)add(idx<<1|1,l,r,w);else add(idx<<1,l,r,w),add(idx<<1|1,l,r,w);t[idx].maxn=Max(t[idx<<1].maxn,t[idx<<1|1].maxn);
}
int main()
{n=read(),m=read();for(int i=1;i<=n;i++)a[i]=read();build(1,1,n);for(int i=1;i<=m;i++){l[i]=read(),r[i]=read();seg[i*2-1]=l[i],seg[i*2]=r[i];}sort(seg+1,seg+2*m+1),seg[0]=0;int cnt=unique(seg+1,seg+2*m+1)-seg-1;seg[cnt+1]=INF;int now=0,f;for(int i=1;i<=n;i++){if(i==seg[now]||(i>seg[now]&&i==seg[now+1])){f=0,cp.clear();if(i==seg[now+1])now++;for(int j=1;j<=m;j++){if(l[j]<=i&&r[j]>=i)f++,add(1,l[j],r[j],-1),cp.push_back(j);}}else if(i>seg[now]){now++,f=0,cp.clear();for(int j=1;j<=m;j++){if(l[j]<=seg[now-1]+1&&r[j]>=seg[now]-1)f++,add(1,l[j],r[j],-1),cp.push_back(j);}}int minnum=a[i]-f;if(t[1].maxn-minnum>ans){ans=t[1].maxn-minnum;A=cp;}if(i==seg[now]-1||i==seg[now]){for(int j=0;j<cp.size();j++)add(1,l[cp[j]],r[cp[j]],1);}}printf("%d\n%d\n",ans,A.size());for(int i=0;i<A.size();i++)printf("%d ",A[i]);return 0;
}

F. MST Unification
题意:给出一个带权无向图,你可以增加任意边的边权使得最小生成树唯一。求所增加的边权总和的最小值。
先用kruskal跑出一个MST,在这个MST上倍增LCA。对于每一条未被加入当前MST的边进行判断,如果其边权与u,v间路径上的最大边权相等,则这条边可以起替代作用(砍掉最大边用这条联通),需要给权值+1。
(选这个LCA做法是因为它在Tutorial只占了三行…写完读了Second Solution发现题解长度和代码长度并不成正比…怎么我选的总是一些莽夫做法)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define Max(a,b) (a>b?a:b)
#define N 200005
using namespace std;
int read()
{int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,head[N],cnt=0,father1[N],dep[N],p[N][20],mlen[N][20];
bool used[N];
struct Node1
{int u,v,w;
}Edges1[N];
bool operator < (Node1 A,Node1 B){return A.w<B.w;}
struct Node2
{int nxt,to,w;
}Edges2[N*2];
int findf(int x)
{return (father1[x]==x)?x:(father1[x]=findf(father1[x]));}
void addedge(int u,int v,int w)
{Edges2[++cnt].nxt=head[u];head[u]=cnt;Edges2[cnt].to=v,Edges2[cnt].w=w;
}
void dfs(int u)
{for(int i=head[u];~i;i=Edges2[i].nxt){int v=Edges2[i].to;if(v==p[u][0])continue;p[v][0]=u,dep[v]=dep[u]+1,mlen[v][0]=Edges2[i].w;dfs(v);}
}
void init()
{for(int i=1;(1<<i)<=n;i++)for(int j=1;j<=n;j++)p[j][i]=p[p[j][i-1]][i-1],mlen[j][i]=max(mlen[j][i-1],mlen[p[j][i-1]][i-1]);
}
int lca(int x,int y)
{int res=0;if(dep[x]>dep[y])swap(x,y);int f=dep[y]-dep[x];for(int i=0;(1<<i)<=f;i++)if(f&(1<<i))res=Max(res,mlen[y][i]),y=p[y][i];if(x!=y){for(int i=(int)log2(n);i>=0;i--)if(p[x][i]!=p[y][i])res=Max(res,mlen[x][i]),res=Max(res,mlen[y][i]),x=p[x][i],y=p[y][i];res=Max(res,mlen[x][0]),res=Max(res,mlen[y][0]),x=p[x][0];}return res;
}
int main()
{memset(head,-1,sizeof(head));memset(dep,0,sizeof(dep));memset(used,0,sizeof(used));n=read(),m=read();for(int i=1;i<=m;i++)Edges1[i].u=read(),Edges1[i].v=read(),Edges1[i].w=read();sort(Edges1+1,Edges1+1+m);for(int i=1;i<=n;i++)father1[i]=i;int cnt=0;for(int i=1;i<=m;i++){int fu=findf(Edges1[i].u),fv=findf(Edges1[i].v);if(fu!=fv){cnt++;addedge(Edges1[i].u,Edges1[i].v,Edges1[i].w);addedge(Edges1[i].v,Edges1[i].u,Edges1[i].w);used[i]=1;father1[fu]=fv; }if(cnt==n-1)break;}dep[1]=mlen[1][0]=0;p[1][0]=1;dfs(1),init();int ans=0;for(int i=1;i<=m;i++){if(used[i])continue;int u=Edges1[i].u,v=Edges1[i].v;int maxlen=lca(u,v);if(maxlen==Edges1[i].w)ans++;}printf("%d\n",ans);return 0;
} 

这是那个Second Solution…只需要在Kruskal时把权值相同的边批量处理。

权值相同的边如果在最开始也加不进去就永远不可能在MST中出现,可以加进去的边有able条,并查集合并实际能用到的边uni条,则其余able-uni条边都需要权值++使MST唯一。

(如果一条有可能加入MST的边由于其他边被先考虑而没加进去,那这条边端点u,v间路径上的最大边权与它的权值相同,即可以拆掉另一条换这条。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define Max(a,b) (a>b?a:b)
#define N 200005
using namespace std;
int read()
{int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,head[N],cnt=0,father1[N],ans=0;
struct Node1
{int u,v,w;
}Edges1[N];
bool operator < (Node1 A,Node1 B){return A.w<B.w;}
int findf(int x)
{return (father1[x]==x)?x:(father1[x]=findf(father1[x]));}
int main()
{memset(head,-1,sizeof(head));n=read(),m=read();for(int i=1;i<=m;i++)Edges1[i].u=read(),Edges1[i].v=read(),Edges1[i].w=read();sort(Edges1+1,Edges1+1+m);for(int i=1;i<=n;i++)father1[i]=i;int cnt=0,able=0,uni=0,from=1;for(int i=1;i<=m;i++){int fu=findf(Edges1[i].u),fv=findf(Edges1[i].v);if(fu!=fv)able++;if(i==m||Edges1[i+1].w!=Edges1[i].w){for(int j=from;j<=i;j++){int fu=findf(Edges1[j].u),fv=findf(Edges1[j].v);if(fu!=fv)father1[fu]=fv,cnt++,uni++;}ans+=able-uni;able=uni=0,from=i;}}printf("%d\n",ans);return 0;
} 

转载于:https://www.cnblogs.com/Zars19/p/10392066.html

Codeforces Round #535 (Div. 3)相关推荐

  1. Codeforces Round #535 (Div. 3) [codeforces div3 难度测评]

    hhhh感觉我真的太久没有接触过OI了 大约是前天听到JK他们约着一起刷codeforces,假期里觉得有些颓废的我忽然也心血来潮来看看题目 今天看codeforces才知道居然有div3了,感觉应该 ...

  2. Codeforces Round #535 (Div. 3)题解

    A. TwodistinctpointsTwo\ distinct\ pointsTwo distinct points 题目大意就是给出两个区间的左右边界,输出两个数,满足两个数分别在两个区间内且这 ...

  3. Codeforces Round #535 (Div. 3) 解题报告

    CF1108A. Two distinct points 做法:模拟 如果两者左端点重合就第二条的左端点++就好,然后输出左端点 #include <bits/stdc++.h> usin ...

  4. Codeforces Round #506 (Div. 3)

    Codeforces Round #506 (Div. 3) 实习期间事不多,对div3 面向题解和数据编程了一波 A. Many Equal Substrings 题目链接 A题就是找后缀和前缀重合 ...

  5. Codeforces Round #563 (Div. 2)/CF1174

    Codeforces Round #563 (Div. 2)/CF1174 CF1174A Ehab Fails to Be Thanos 其实就是要\(\sum\limits_{i=1}^n a_i ...

  6. 构造 Codeforces Round #302 (Div. 2) B Sea and Islands

    题目传送门 1 /* 2 题意:在n^n的海洋里是否有k块陆地 3 构造算法:按奇偶性来判断,k小于等于所有点数的一半,交叉输出L/S 4 输出完k个L后,之后全部输出S:) 5 5 10 的例子可以 ...

  7. Codeforces Round #696 (Div. 2) (A ~ E)超高质量题解(每日训练 Day.16 )

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #696 (Div. 2) (A ~ E)超高质量题解 比赛链接:h ...

  8. Codeforces Round #712 Div.2(A ~ F) 超高质量题解(每日训练 Day.15 )

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #712 Div.2(A ~ F) 题解 比赛链接:https:// ...

  9. Codeforces Round #701 (Div. 2) A ~ F ,6题全,超高质量良心题解【每日亿题】2021/2/13

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A - Add and Divide B - Replace and Keep Sorted C ...

  10. Codeforces Round #700 (Div. 2) D2 Painting the Array II(最通俗易懂的贪心策略讲解)看不懂来打我 ~

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 整场比赛的A ~ E 6题全,全部题目超高质量题解链接: Codeforces Round #700 ...

最新文章

  1. 记录一次生产环境中Redis内存增长异常排查全流程!
  2. 使用 yum 安装Docker(CentOS 7下)
  3. ansible调用callbacks插件实现结果nosql输出回调
  4. Python中的Numpy模块(1,numpy创建)
  5. mysql榨包是什么意思_模块与包 Mysql与Oracle区别
  6. Clumsy 弱网络环境模拟工具使用介绍
  7. sdk怎么用_PLC不支持OPC UA怎么办?别问了看完你就懂了
  8. RabbitMQ安装|使用|概念|Golang开发
  9. webpack -- 无法将“webpack”项识别为 cmdlet 。。。
  10. [HTTP] HTTP消息
  11. 【电子签章】HTML格式合同转化成PDF文件 已下载
  12. Altium AD20分屏显示,交叉选择模式使用,原理图和PCB器件的同步选择
  13. ZUST蓝桥杯校内选拔赛(java,c)安吉校区
  14. Linux下可用的开源网络调试助手
  15. 马斯克:让我成功的其实是工程思维
  16. virtualization technology设置
  17. 前端开发必备(三)-----用js验证表单是否为空以及验证码是否输入正确
  18. 计算机开机没有显示是什么原因是什么情况,电脑开机后显示器没有反应解决方法...
  19. K-means 算法(基本用法)
  20. scanf()函数的用法

热门文章

  1. sqlserver2008r2通过发布和订阅的方式进行数据库同步
  2. poj_3468 伸展树
  3. 第九讲 自定义函数参数预定义
  4. TFS2010物理迁移workspace恢复
  5. 初入职场,你够聪明不?
  6. 织梦本地调试运行PHP不显示图片,织梦CMS手机端不显示图片的原因及解决方法!...
  7. (转)DPDK收发包处理流程01 -- 网卡初始化
  8. DPDK初始化分析(一)
  9. gdb调试出现“no debugging symbols found”
  10. Wifi Enable 启动过程