Codeforces Round #378 (Div. 2)
第一次打算rating的cf,作此文留个纪念吧。顺便提醒自己把坑填了。
A,B都是水题,没啥好说的。不过感觉自己写的好慢。
C题题干好长,看了一下D题A的人更多,于是去看D题。
开始想的是直接按照长和宽排个序,交了一发WA了之后发现可以旋转的情况根本没有考虑。
然后就想用map乱搞,对于每个面维护一个最大值。交上去还是WA。
发现电脑很坑爹地-和=分不太清楚,于是被坑了。终于把D题A掉了
以为比赛是两个小时,都准备洗洗睡了才发现时间不对。
C题想到了分块,但是构造方案感觉很麻烦,应该是贪心构造,但是处理数组下标之类的问题会很费劲。
比赛结束不久交了一发随便构造的,发现WA了,因为可能有解的情况搞成无解了。
刚刚交了一发贪心的,构造的时候一是合并之后最大的优先。
证明应该很容易,考虑最大的一项,如果它不能合并,一定无解。因为其左端,右端必与中间相等。
所以要合并的话肯定是合并最大的。当然,如果直接按照上述证明找左右端点会很麻烦。
为了减少编程复杂度,我算数组下标都直接用vector的erase删除来维护了。。
注意erase不是earse
E,F占坑
UPD:
F题是个很好的题目。
题意:给顶一个无向图,每条边有一个权值Wi和一个数值Ci,Ci表示将这条边的权值减小1所需要花费的金钱,花费金钱后允许这条边的权值为负数。在总花销不超过K的情况下求改造完的图的最小生成树的最小值。(2 ≤ n ≤ 2·105, n - 1 ≤ m ≤ 2·105)
题解:
考虑最终的结果,由于允许负权边的存在,所以必定是把所有的金钱都用到一条边上以使得能够减小的权值尽量大,而且这条边的Ci一定是整个树中最小的,即如果这条边不能再减小权值,所剩余的金钱不够其他任何一条边减少1。
由此我们可以得到一个策略:枚举每一条边,假设它就是在结果中减少权值的边,修改这条边的权值以后,其他边的权值不变,求最小生成树。时间复杂度O(m^2 log m)对于本题的数据范围来说慢了一些。
对于这一策略显然枚举的过程我们很难优化使得时间复杂度降低。而我们如果起初以wi为边权求出最小生成树。如果我们枚举的这条边减小权值,加入到最小生成树中,就会形成一个环,而我们要做的是求这个环上的最大边权。如何去求呢?假设我们新加入的这条边连接两点u和v,则我们求这两点的LCA,从而在O(log n)的时间内实现查询操作。综上,算法的复杂度是O(mlogm + nlogn)
贴一下这个题的代码,看起来会比较鬼畜 = = 因为需要开long long我是按int写完直接把int全替换成long long了。想增加可读性的话就把long long再替换回来吧。。
#include<cstdio> #include<iostream> #include<cstring> #include<vector> #include<algorithm> using namespace std; const long long maxn=200050; const long long maxlog=20; const long long INF=2147483647; struct Edge{ long long from,to,dist,id; bool operator<(const Edge& a) const{ return dist<a.dist; } Edge(long long u=0,long long v=0,long long w=0,long long t=0):from(u),to(v),dist(w),id(t) {} }; bool vis[maxn]; vector<Edge> edges,edges_set; vector<long long> G[maxn]; //?????????С?????? long long ans,anspos,mst_ans,n,m,S; long long c[maxn],w[maxn],p[maxn],deep[maxn],father[maxn][maxlog],fatherw[maxn][maxlog]; long long getfather(long long x){ return p[x]==x?x:p[x]=getfather(p[x]); } void AddEdge(long long from,long long to,long long dist,long long id){ edges.push_back(Edge(from,to,dist,id)); edges.push_back(Edge(to,from,dist,id)); long long m1=edges.size(); G[from].push_back(m1-2); G[to].push_back(m1-1); } void bulid_mst() { ans=0; mst_ans=0; for(long long i=0;i<n;i++) p[i]=i; sort(edges_set.begin(),edges_set.end()); for(long long i=0;i<edges_set.size();i++){ long long x=getfather(edges_set[i].from),y=getfather(edges_set[i].to); if(x!=y){ vis[i]=true; p[x]=y; ans+=edges_set[i].dist; mst_ans+=edges_set[i].dist; AddEdge(edges_set[i].from,edges_set[i].to,edges_set[i].dist,edges_set[i].id); } } } void dfs(long long u){ for(long long i=0;i<G[u].size();i++){ Edge e=edges[G[u][i]]; if(e.to!=father[u][0]){ father[e.to][0]=u; deep[e.to]=deep[u]+1; fatherw[e.to][0]=e.dist; dfs(e.to); } } } /* father[i][j]=father[father[i][j-1]][j-1] fatherw[i][j]=max(fatherw[i][j-1],fatherw[father[i][j-1][j-1]); */ void get_function() { for(long long j=1;j<maxlog;j++) for(long long i=0;i<n;i++) if(father[i][j-1]!=-1){ father[i][j]=father[father[i][j-1]][j-1]; fatherw[i][j]=max(fatherw[i][j-1],fatherw[father[i][j-1]][j-1]); } // for(long long j=1;j<maxlog;j++) // for(long long i=0;i<n;i++) prlong longf("father[%d][%d]=%d,fatherw[%d][%d]=%d \n",i,j,father[i][j],i,j,fatherw[i][j]); } long long goup_upweight(long long& u,long long k){ long long ans=-INF; for(long long i=0;i<maxlog;i++){ if(k&1){ ans=max(ans,fatherw[u][i]); u=father[u][i]; } k>>=1; } return ans; } long long together_upweight(long long& u,long long& v){ long long ans=-INF; while(1){ long long j=maxlog-1; while(j>=0 && father[u][j]==father[v][j]) j--; // prlong longf("%d %d %d %d %d\n",u,v,father[u][j],father[v][j],j); // cout<<j<<endl; if(j==-1){ ans=max(ans,fatherw[u][0]); ans=max(ans,fatherw[v][0]); u=father[u][0]; v=father[v][0]; break; } else{ ans=max(ans,fatherw[u][j]); ans=max(ans,fatherw[v][j]); u=father[u][j]; v=father[v][j]; } } return ans; } long long query(long long u,long long v) { long long ans=-INF; if(deep[u]<deep[v]) swap(u,v); if(deep[u]>deep[v]) ans=max(ans,goup_upweight(u,deep[u]-deep[v])); // prlong longf("deep[%d]=%d,deep[%d]=%d\n",u,deep[u],v,deep[v]); if(u!=v) ans=max(ans,together_upweight(u,v)); return ans; } void init() { scanf("%I64d%I64d",&n,&m); for(long long i=0;i<m;i++) scanf("%I64d",&w[i]); for(long long i=0;i<m;i++) scanf("%I64d",&c[i]); for(long long i=0;i<m;i++){ long long from,to; scanf("%I64d%I64d",&from,&to); from--;to--; edges_set.push_back(Edge(from,to,w[i],i)); } scanf("%I64d",&S); bulid_mst(); memset(father,-1,sizeof(father)); memset(fatherw,-1,sizeof(fatherw)); father[0][0]=-1;deep[0]=0; dfs(0); get_function(); } void work() { for(long long i=0;i<edges_set.size();i++){ Edge e=edges_set[i]; long long t=e.dist-(S/c[e.id]),t0=query(e.from,e.to); // prlong longf("dist=%d,down=%d,t=%d\n",e.dist,S/c[e.id],t); long long now=mst_ans-t0+t; if(now<ans){ ans=now; anspos=i; } } cout<<ans<<endl; memset(vis,false,sizeof(vis)); Edge& e=edges_set[anspos]; e.dist-=S/c[e.id]; bulid_mst(); for(long long i=0;i<edges_set.size();i++) if(vis[i]) cout<<edges_set[i].id+1<<" "<<edges_set[i].dist<<endl; } int main() { #ifdef LOCAL freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif init(); work(); fclose(stdin); fclose(stdout); return 0; }