暑期集训日志(Day0~Day5)
章·五:2019-07-15:明月不谙离恨苦,斜光到晓穿朱户
·昨日小结:
昨天考试又是爆零边缘,除了难过就剩难过了。
T1暴力打崩了只拿了5分。
T2没给分时间。最后20分钟打了个残码。没仔细观察数据范围,应该骗到手的15分菊花图和5分链都没看到。
T3推了一半的式子,容斥和dp都推出来了,就差g数组辅助,但是没有时间了……
我好失败啊……
还是自己太渣,别找客观借口。
继续努力吧。这次考试都来了,下次考试还会远吗/恐惧.jpg
·今日进度
[0714模拟赛]A.(暴搜)
又是一道论暴搜艺术的题目。
码的好的80,差一点的40,再差的20,我拿了5分。。
别人都是nq的时间复杂度,我码了n2。我……真是个sb吧……
最后还被数据范围卡住了。。我……
代码不放了祝大家幸福……我滚去追求卓越了……呜呜呜……
[0714模拟赛]C.(组合数学+容斥原理)
额,考试的时候死在这道题上了。看了题解,前半部分是我在考试的时候就想出来的。
包括容斥和一点dp。$C_{n-1}^2$的式子也是在考场上推出来的。
但是没想到的是可以另开一个g数组处理状态转移的数据。
其实之前看到了wba某题题解中提到了可以用一个额外的g数组来辅助状态转移但没有注意。
以后还是要注意一下这些东西啊QAQ。
[0714模拟赛]B.(树dp+概率)
一会儿写个详细的题解……光是题解就看了三份(能拿到手的题解都看了)
还是要和利哥合计一下才能彻底理解明白。然而代码不会打,还是颓了……
这题绝对不是人做的
·随手记
09:38:43
今天好顺利啊,loj的今日运势终于准了一会……
到9:00的时候就已经A掉昨天的T1和T3了,T2全场只有wd神犇A掉了?
还是想说自己就是个sb。实力不行还不努力,随波逐流一起浪,最后还得滚回去肝高考……
我这是为了什么?
上次犯错误被流放到11机房的时候,吕教练说了一句话给我的触动挺大的。
然后我戒掉了颓代码。但是仍然和lyl闲聊,我真tm闲的慌。
我文化课很渣,奥赛也渣。真想不出我还有什么理由继续颓废下去。
学奥赛,最忌避重就轻,避难就易啊。
改变一下,迎难而上,继续努力下去吧。
另外,不能老是问了啊。学奥赛就是要自己认真肝下去。
说什么三人行必有我师,说什么集百家之长,都是空话,自己实力的提升才是自己的。
14:28:38
T2的题解根本不是人能看懂的……
顺便说一句在网上一不小心搜到了学长的题解,说好的原创题呢?
不过学长的代码和老师给的std好像啊hhh。然而并看不懂啊。
谁能救救我?在线等挺急的QAQ。
17:28:57
新的考试又放出来了。。。我真tmd乌鸦嘴。想想也是,老师说放假之前要考五场,第四场还没考……
对啦明天期末考试,祝化奥生们考一个好成绩 /滑稽
我的成绩可全靠他们顶住了……
章·四:2019-07-14:落日照大旗,马鸣风萧萧
·昨日小结
昨天颓废的有点多,颓图还被路过的学长看到了……
我真想找块砖头……抱着哭一会儿。
晚上状态奇佳,手码tarjan,码了三道题(有一道题是dfs卡常过去的)
码不出来也没有特别颓废比如颓代码砸键盘之类的……
之前真是打扰各位大佬了 /对不起/对不起/对不起/对不起/对不起/对不起
下面真得努力了啊……QAQ
·今日进度
[tarjan]B.「压力」(tarjan点双连通分量)
大佬说在这道题上卡了四个多小时我还不信。
直到自己也卡了四个多小时……
打代码因为连打带颓,比较慢,而且思路混乱,打了一个多小时。终于打出来啦交!
RE0……这是个×啊……
问动动神佬,神佬说数组开小了。好吧开十倍,不RE改WA了QAQ,分数倒是挺稳定。
后来发现是建边方式错了。应该建无向,我按有向建的所以原地自爆。
改了改几处玄学错误,完美AC(为啥在BZOJ上跑了8000ms??自家oj1400ms……反正慢就是了……)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<stack> #include<vector> #define rint register int #define read(aa) aa=init() using namespace std; int n,m,Q,tot_e,first[1000005],first_q[1000005],ans[1000005]; struct node{int u,v,nxt;}edge[1000005],edge_q[1000005]; inline int init() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+(ch-'0');ch=getchar();} return a*b; } inline void add(int uu,int vv) { ++tot_e; edge[tot_e].u=uu; edge[tot_e].v=vv; edge[tot_e].nxt=first[uu]; first[uu]=tot_e; } inline void add_q(int uu,int vv) { ++tot_e; edge_q[tot_e].u=uu; edge_q[tot_e].v=vv; edge_q[tot_e].nxt=first_q[uu]; first_q[uu]=tot_e; } int cnt,dfn[1000005],low[1000005],sum,tot_q; int belong[1000005],cf[1000005],root; bool cut[200005],cutt[200005]; stack <int> s; vector <int> v[200001]; inline void tarjan(int x) { // cout<<x<<endl; dfn[x]=low[x]=++cnt; s.push(x); int flag=0; for(rint i=first[x];i;i=edge[i].nxt) { int y=edge[i].v; if(!dfn[y]) { tarjan(y);low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { flag++; if(x!=root||flag>1)cut[x]=true; tot_q++; while(1) { int top=s.top();s.pop(); v[tot_q].push_back(top); if(top==y)break; // cout<<"bb"<<endl; } v[tot_q].push_back(x); } } else low[x]=min(low[x],dfn[y]); } } queue <int> q; int dep[200005],fa[200005][21]; inline void bfs() { q.push(1);dep[1]=1; while(!q.empty()) { int x=q.front();q.pop(); for(rint i=first_q[x];i;i=edge_q[i].nxt) { int y=edge_q[i].v; if(dep[y])continue; dep[y]=dep[x]+1; fa[y][0]=x; for(rint i=1;i<=20;++i) fa[y][i]=fa[fa[y][i-1]][i-1]; q.push(y); } } return ; } inline int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(rint i=20;i>=0;--i) { if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; } if(x==y)return x; for(rint i=20;i>=0;--i) { if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; } return fa[x][0]; } bool vis_cf[200005]; inline void dfs_cf(int x) { vis_cf[x]=true; for(rint i=first_q[x];i;i=edge_q[i].nxt) { int y=edge_q[i].v; if(vis_cf[y])continue; dfs_cf(y); cf[x]+=cf[y]; } } int new_id[200005]; int main() { read(n),read(m),read(Q); int a,b;root=1; for(rint i=1;i<=m;++i) { read(a),read(b); add(a,b);add(b,a); } /*"这个世界是连通的"出题人万岁^-^*/ tarjan(1); // cout<<"aa"<<endl; int num=tot_q; for(rint i=1;i<=n;++i) if(cut[i]) belong[i]=++num; tot_e=0; /* for(rint i=1;i<=n;++i) for(rint j=first[i];j;j=edge[j].nxt) { int y=edge[j].v; if(belong[i]==belong[y])continue; add_q(belong[i],belong[y]); } */ for(rint i=1;i<=tot_q;++i) { // cout<<v[i].size()<<endl; int ss=v[i].size(); for(rint j=0;j<ss;++j) { int x=v[i][j]; if(cut[x]) { add_q(i,belong[x]); add_q(belong[x],i); } else belong[x]=i; } } // cout<<"bfs1"<<endl; bfs(); // cout<<"bfs2"<<endl; for(rint i=1;i<=Q;++i) { read(a),read(b); cf[belong[a]]++,cf[belong[b]]++; int l=lca(belong[a],belong[b]); cf[l]--,cf[fa[l][0]]--; if(!cut[a])ans[a]++; if(!cut[b])ans[b]++; } // cout<<"aa"<<endl; dfs_cf(1); // cout<<"cfws"<<endl; for(rint i=1;i<=n;++i) { if(cut[i])cout<<cf[belong[i]]<<endl; else cout<<ans[i]<<endl; } return 0; }
·随手记
8:22:16
距离考试还有五个半小时,woc好慌啊QAQ,鬼知道老师又要出什么变态题目。
APIO?IOI?woc好害怕啊QAQ, 恐惧.jpg 算了接着打第四题。 一秒正经.png
ps.我是颓狗,我要退登。不过第二题绝不登录!
11:05:32
饿~下午我能买点吃的嘛……
教练:(一边吃一边说)别在机房吃东西啊。
13:51:01
考试啦…… /爆零恐惧.jpg
19:23:11
五分……我太渣了。又垫底了。滚去追求卓越吧还是。
章·三:2019-07-13:凭君莫话封侯事,一将功成万骨枯
·昨日小结
昨天最后还是颓了。因为听barca说,天天爱跑步需要打线段树和树上差分。
发现Larry和Barca都不会树上差分(Barca是会操作但不理解)
我恰好拜读过动动大佬关于树上差分的随笔。于是一场纸上谈兵开始了。
恩,二十分钟没了。然后Barca说这道题还需要用到线段树。
我忽然意识到Larry在孙科学长讲线段树的时候并不在(因肺炎支原体感染)
我就给Larry讲了线段树进阶第一题:永无乡。顺便介绍了一点主席树。
然后剩下的一个小时,Barca给我们讲了天天爱跑步的思想。(然而还是不会打)。
在这里感谢Barca和Larry(虽然他们支持不同的球队),
在我们互相讲解的过程中我对线段树和树上差分的理解又深了一层。
·今日进度
[图论]G.「天天爱跑步」(线段树+LCA+树上差分)
这道题真令人质壁分离……不过也来的挺及时。它让我好好复习了一下线段树和树上差分。
卡了半天。总算是过去了。后期肯定要写一个详细一点的题解(至于后期要后期到什么时候嘛……)。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<cmath> #define rint register int using namespace std; struct node{int u,v,next;}edge[600005]; struct tree{int st,en,go;}lp[300005]; int n,tot_e,cnt,m,num,in_x,in_y,first[300005],deep[300005],ldfn[300005],rdfn[300005]; int lc[300005<<6],rc[300005<<6],w[300005],p[300005][22],ans[300005],root[300005<<6]; int qyqyooo[300005<<6],size[300005]; void add(int x,int y) { tot_e++; edge[tot_e].u=x; edge[tot_e].v=y; edge[tot_e].next=first[x]; first[x]=tot_e; } void dfs(int x) { ldfn[x]=++num; size[x]=1; for(int i=first[x];i;i=edge[i].next) { int v=edge[i].v; if(v==p[x][0])continue; p[v][0]=x; for(rint i=1;i<=20;++i) p[v][i]=p[p[v][i-1]][i-1]; deep[v]=deep[x]+1; dfs(v); size[x]+=size[v]; } rdfn[x]=num; }/* void get_fa() { for(rint i=1;i<=n;i++) p[i][0]=fa[i]; for(rint i=1;i<=20;i++) for(rint j=1;j<=n;j++) if(p[j][i-1]!=0) p[j][i]=p[p[j][i-1]][i-1]; }*/ int LCA(int x,int y) { if(deep[x]<deep[y]) swap(x,y); int k=deep[x]-deep[y]; for(rint i=20;i>=0;i--) if(k-(1<<i)>=0) { k-=(1<<i); x=p[x][i]; } if(x==y) return x; for(rint i=20;i>=0;i--) if(p[x][i]!=0&&p[x][i]!=p[y][i]) { x=p[x][i]; y=p[y][i]; } return p[x][0]; } void change(int x,int num,int le,int ri,int &now) { if(x==0) return; if(now==0) now=++cnt; qyqyooo[now]+=num; if(le==ri) return; int mid=(le+ri)>>1; if(x<=mid) change(x,num,le,mid,lc[now]); else change(x,num,mid+1,ri,rc[now]); } int search(int lr,int rr,int le,int ri,int now) { if(now==0) return 0; if(lr==le&&rr==ri) return qyqyooo[now]; int mid=(le+ri)>>1; if(rr<=mid) return search(lr,rr,le,mid,lc[now]); if(lr>mid) return search(lr,rr,mid+1,ri,rc[now]); else return search(lr,mid,le,mid,lc[now])+search(mid+1,rr,mid+1,ri,rc[now]); } int main() { scanf("%d %d",&n,&m); for(rint i=1;i<n;i++) { scanf("%d %d",&in_x,&in_y); add(in_x,in_y);add(in_y,in_x); } for(rint i=1;i<=n;i++)scanf("%d",&w[i]); dfs(1);//get_fa(); for(rint i=1;i<=m;i++) { scanf("%d %d",&lp[i].st,&lp[i].en); lp[i].go=LCA(lp[i].st,lp[i].en); } for(rint i=1;i<=m;i++) { change(ldfn[lp[i].st],1,1,n,root[deep[lp[i].st]]); change(ldfn[p[lp[i].go][0]],-1,1,n,root[deep[lp[i].st]]); } for(rint i=1;i<=n;i++) ans[i]+=search(ldfn[i],rdfn[i],1,n,root[deep[i]+w[i]]); for(rint i=1;i<=m;i++) { change(ldfn[lp[i].en],1,1,n,root[deep[lp[i].st]-2*deep[lp[i].go]+2*n]); change(ldfn[lp[i].go],-1,1,n,root[deep[lp[i].st]-2*deep[lp[i].go]+2*n]); } for(rint i=1;i<=n;i++) ans[i]+=search(ldfn[i],rdfn[i],1,n,root[w[i]-deep[i]+2*n]); for(rint i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }
[tarjan]A.「BLO」(tarjan求割点)
挺果的一道题,但是我弱啊QAQ。一个多小时看了看李煜东那本书上关于tarjan的详解,
然后想切掉这道题,结果T掉了。我好像是全衡中机房,算上山大附中机房第一个T的人……真尴尬。
真个人都崩了以为算法出了问题,转去大视野评测发现是WA,
感觉即使数据不一样,评测机不同也不会差这么多,3000ms和700ms。仔细查了一下发现读入边的参数写错了……
A掉。(最开始以为数组问题所以我数组开得贼大……)
所以这是我第一道并肩天皇超越miku的题目??(之前好像还有一道矩阵游戏hhh)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<stack> #define rint register int #define int long long using namespace std; int n,m,tot; inline int init() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+(ch-'0');ch=getchar();} return a*b; } int tot_e,first[1000005]; struct node{int v,nxt;}edge[1000006]; inline void add(int uu,int vv) { ++tot_e; edge[tot_e].v=vv; edge[tot_e].nxt=first[uu]; first[uu]=tot_e; } int ans[1000005],dfn[1000005]; int low[1000005],size[1000005],num; bool cut[1000005]; inline void tarjan(int x) { dfn[x]=low[x]=++num;size[x]=1; int flag=0,sum=0; for(rint i=first[x];i;i=edge[i].nxt) { int y=edge[i].v; if(dfn[y]){low[x]=min(low[x],dfn[y]);continue;} tarjan(y); size[x]+=size[y]; low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { flag++;//记录满足low[y]>=dfn[x]的y的个数 ans[x]+=size[y]*(n-size[y]); sum+=size[y]; if(x!=1||flag>1)cut[x]=1; } } if(cut[x])ans[x]+=(n-sum-1)*(sum+1)+(n-1); else ans[x]=2*(n-1); } signed main() { n=init(),m=init(); // cout<<n<<" "<<m<<endl; tot=1; for(rint i=1,x,y;i<=m;++i) { x=init(),y=init(); if(x!=y) add(x,y),add(y,x); } tarjan(1); for(rint i=1;i<=n;++i) cout<<ans[i]<<endl; return 0; }
[tarjan]C.「连通数」(tarjan+bitset论暴搜的艺术)
这道题正解是bitset。然而不追求卓越的我用dfs爆搜A掉……我错了我错了我错了……
不过真的是要论一下暴搜的艺术。kq神佬没卡常,爆搜1A……我……我卡了常三次才A掉。。
不说了代码见,看看我究竟有多傻……
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int first[2005],tot; struct node{int u,v,nxt;}edge[2005*2005]; int n,ans; char st[2005]; bool vis[2005]; inline int init() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+(ch-'0');ch=getchar();} return a*b; } inline void add(int uu,int vv) { ++tot; edge[tot].u=uu; edge[tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } inline void dfs(int x) { vis[x]=1; for(rint i=first[x];i;i=edge[i].nxt) { int v=edge[i].v; if(!vis[v])dfs(v); } return ; } int main() { n=init(); for(rint i=1;i<=n;i++) { scanf("%s",st+1); for(rint j=1;j<=n;j++) if(st[j]=='1')add(i,j); } for(rint i=1;i<=n;++i) { for(rint j=1;j<=n;++j) vis[j]=0; dfs(i); for(rint j=1;j<=n;++j) if(vis[j])ans++; } cout<<ans<<endl; return 0; }
打出来之后挺开心,以为能1A,然后T60……
问过wba神佬后削了一下常数,开了ans数组最后累加
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int first[2005],tot; struct node{int v,nxt;}edge[2005*2005]; int n,ans[2005],anss; char st[2005]; bool vis[2005]; inline int init() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+(ch-'0');ch=getchar();} return a*b; } inline void add(int uu,int vv) { ++tot; edge[tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } inline void dfs(int st,int x) { vis[x]=1; ans[st]++; for(rint i=first[x];i;i=edge[i].nxt) { int v=edge[i].v; if(!vis[v])dfs(st,v); } return ; } int main() { n=init(); for(rint i=1;i<=n;i++) { scanf("%s",st+1); for(rint j=1;j<=n;j++) if(st[j]=='1')add(i,j); } for(rint i=1;i<=n;++i) { for(rint j=1;j<=n;++j) vis[j]=0; dfs(i,i); } for(rint i=1;i<=n;++i) anss+=ans[i]; cout<<anss<<endl; return 0; }
还是难受,动动神佬看不下去了,过来打脸蒟蒻:你这ans直接在dfs里面累加不就完了?又帮我加了一堆卡常。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int first[2005],tot; struct node{int v,nxt;}edge[4000005]; int n,ans[2005],anss; char st[2005]; bool vis[2005]; inline void add(rint uu,rint vv) { edge[++tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } inline void dfs(rint st,rint x) { vis[x]=1; anss++; for(rint i=first[x];i;i=edge[i].nxt) { rint v=edge[i].v; if(!vis[v])dfs(st,v); } return ; } int main() { scanf("%d",&n); for(rint i=1;i<=n;i++) { scanf("%s",st+1); for(rint j=1;j<=n;j++) if(st[j]=='1')add(i,j); } for(rint i=1;i<=n;++i) { for(rint j=1;j<=n;++j) vis[j]=0; dfs(i,i); } cout<<anss<<endl; return 0; }
依旧T掉了……动动大佬对我绝望了,放弃了我。
我发了发狠,放弃清空vis数组开了一波空间换时间过掉了……
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int n,ans[2005],anss,first[2005],tot; struct node{int v,nxt;}edge[4000005]; char st[2005]; bool vis[2005][2005]; void add(rint uu,rint vv) { edge[++tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } void dfs(rint st,rint x) { vis[st][x]=1; anss++; for(rint i=first[x];i;i=edge[i].nxt) { rint v=edge[i].v; if(!vis[st][v])dfs(st,v); } return ; } int main() { scanf("%d",&n); for(rint i=1;i<=n;i++) { scanf("%s",st+1); for(rint j=1;j<=n;j++) if(st[j]=='1')add(i,j); } for(rint i=1;i<=n;++i)dfs(i,i); cout<<anss<<endl; return 0; }
暴搜T到飞起系列
[tarjan]D.「Redundant Paths 分离的路径」(tarjan无向图求强连通分量)
我终于过掉了。尝试了两种方法,一种是tarjan强连通分量缩点,一种是求割边然后硬算。
一种WA18,一种是RE0。打算最后半小时用边双打一遍,结果偶然听wba大佬说直接求无向图强连通缩点就行。
咦那不是我的第一种方法咩。在tarjan函数里面加了个特判,不让它搜回去。WA27。难受。
偶然发现自己最后输出似乎搞错了。改了一下91分。加上建边优化终于A掉了。/苍天有眼/拜谢大佬
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<stack> #define rint register int using namespace std; int F,R,a,b,tot,first[5003],tot_l,first_q[5003]; struct node{int u,v,nxt;}edge[10004],edge_q[10004]; bool map[5003][5003]; inline void add(int uu,int vv) { ++tot; edge[tot].u=uu; edge[tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } inline void add_q(int uu,int vv) { ++tot_l; edge_q[tot_l].u=uu; edge_q[tot_l].v=vv; edge_q[tot_l].nxt=first_q[uu]; first_q[uu]=tot_l; } int dfn[5003],low[5003],cnt,tot_q,belong[5003],ans; int du[5003]; bool instack[5003]; stack <int> s; /* inline void tarjan(int x) { dfn[x]=low[x]=++cnt; s.push(x);instack[x]=true; for(rint i=first[x];i;i=edge[i].nxt) { int y=edge[i].v; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if(instack[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { ++tot_q; while(1) { int ll=s.top();s.pop(); instack[ll]=false; belong[ll]=tot_q; if(ll==x)break; } } } */ inline void tarjan(int fa,int x) { dfn[x]=low[x]=++cnt; s.push(x);instack[x]=true; for(rint i=first[x];i;i=edge[i].nxt) { int y=edge[i].v; if(y==fa)continue; if(!dfn[y]) { // cout<<x<<"->"<<y<<endl; tarjan(x,y); low[x]=min(low[y],low[x]); // printf("low[%d]被%d更新为%d\n",x,y,low[x]); } else if(instack[y]) { // cout<<"##"<<x<<"->"<<y<<endl; low[x]=min(dfn[y],low[x]); // printf("##low[%d]被%d更新为%d\n",x,y,low[x]); } } if(dfn[x]==low[x]) { ++tot_q; while(1) { int lin=s.top(); s.pop();instack[lin]=false; belong[lin]=tot_q; if(lin==x) break; } } return ; } int main() { scanf("%d %d",&F,&R); for(rint i=1;i<=R;++i) { scanf("%d %d",&a,&b); if(!map[a][b]) { add(a,b),add(b,a); map[a][b]=map[b][a]=1; } } for(rint i=1;i<=F;++i) if(!dfn[i])tarjan(0,i); // for(rint i=1;i<=F;++i)printf("dfn[%d]=%d,low[%d]=%d\n",i,dfn[i],i,low[i]); // for(rint i=1;i<=F;++i)cout<<belong[i]<<endl; for(rint i=1;i<=F;++i) { for(rint j=first[i];j;j=edge[j].nxt) { int vv=edge[j].v; if(belong[vv]==belong[i])continue; add_q(belong[vv],belong[i]); du[belong[i]]++; } // cout<<belong[i]<<endl; } for(rint i=1;i<=tot_q;++i) if(du[i]==1)ans++; ans=(ans+1)>>1; cout<<ans<<endl; return 0; }
·随手记
10:33:45
学长突然出现把图论专题pass掉了……我的图论啊
我的天天爱跑步啊……刚刚想出来思路还没打……我还想A掉这到题目啊……
不行不行不能颓废了接受现实去打tarjan……
14:20:36
还是在颓,找不到状态QAQ。让我找个借口,网上大佬们没有人有写一个tarjan算法详解的闲心吗QAQ,蒟蒻真的需要啊QAQ。
有没有人救救我……我不会tarjan啊QAQ。
15:10:47
强迫自己看李煜东终于看懂了一点东西。
继续努力吧~
ps.感觉这东西越写越长。我是不是应该五天放在一篇里。
学长说这是改错本,改错本写这么糟心真的好么……
ps.ps.刚刚放松五分钟的时候把这篇博文复制到了word里发现不算代码已经两千九百多字了……
我tm真闲……怪不得我冲不到前面去……
ps.ps.ps退登博客园ing~
17:00:32
教练谈了一下学习习惯的问题。
感觉自己的学习方向和学习状态都偏了……纠正一下。
17:27:36
认真看书的蒟蒻出来放一个tarjan的模板:无向图tarjan求割边
加上本蒟蒻蒟蒻视角的详解~
/*无向图tarjan求桥(割边)*/ void tarjan(int x,int in)//为了处理重边问题,这里我们第二个参数为进入该点的边的编号 { dfn[x]=low[x]=++num;//初始化时间戳和追溯标记 for(int i=first[x];i;i=edge[i].nxt) { int y=edge[i].v;//取出目标节点 if(!dfn[y])//该点没有被访问过 { tarjan(y,i);//进行tarjan操作获取该点信息 low[x]=min(low[x],low[y]);//更新本节点的追溯值 if(low[y]>dfn[x])//利用目标节点判断出边是否割边 bridge[i]=bridge[i^1]=true;//bool bridge用于记录边是否割边 } else if(i!=(in^1))//注意这里要写(in^1)表示反边,具体原因结合链式前向星储存方式理解 low[x]=min(low[x],dfn[y]);//利用目标节点更新本节点信息 } return ; }
ps.具体代码脱自李煜东《算法竞赛进阶指南》,%%%作者
21:06:11
挺难受的。特别想A掉tarjan的D题。甚至动了歪念头(颓个代码吧,颓个代码吧~)
刚刚打了一个普通tarjan上去,以为是对的。但是都输出以后我发现,tarjan普通算法适用与有向图。
倒不是说我刚发现这道题是无向图,只是之前对tarjan的理解还是不够透彻。
然后打了一个求割边,脑补缩点过程又打爆了。调tarjan的过程真是一个考验耐心的过程。
继续吧。即使今天A不掉我也绝对不会颓废的!
章·二:2019-07-12:男儿何不带吴钩,收取关山五十州
·今日进度
[图论]C.「约会 Rendezvous」(基环树+LCA)
这道题和我犯冲……
开始我坚持自己打,仅仅听lockey大神说是基环树。
查了一下基环树,后来早饭的时候碰见了starsing神,starsing神说和I题一样。
蒟蒻这才明白自己不知不觉水过了一道基环树。
然后就打了tarjan、LCA,但是最后输出的时候判断太多,
前面求得数组又太杂,太难调用。本来想打并查集优化一下的,但崩了……
最后颓了题解(已经是三个小时以后)还交错码了……整个人都不好了……
然后T94,T97,T94……我一怒之下开了超级快读看你T不T了。
const int L=1<<20|1; char buffer[L],*S,*T; #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) int read() { rint a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=a*10+ch-'0';ch=getchar();} return a*b; }
颓码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #define rint register int const int L=1<<20|1; char buffer[L],*S,*T; #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) using namespace std; int n,m,head[500005],tot,fat[500005]; int dex,cnt,t,bar[500005],bl[500005],ac[500005]; int d[500005],f[500005][20],l_a[500005],l_b[500005]; vector<int>dell[500005];queue<int>q; struct node{int to,nxt;}edge[500005]; int read() { rint a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=a*10+ch-'0';ch=getchar();} return a*b; } void add(rint x,rint y) { edge[++tot].to=y; edge[tot].nxt=head[x]; head[x]=tot; } int find(rint x) { if(fat[x]==x) return x; return fat[x]=find(fat[x]); } void get_dell(rint x,rint dex) { bar[x]=dex; for(rint i=head[x];i;i=edge[i].nxt) { rint y=edge[i].to; if(bar[y]==dex) { ++cnt; while(y!=x) { dell[cnt].push_back(x); x=ac[x]; } dell[cnt].push_back(y); } else ac[y]=x,get_dell(y,dex); } } void bfs(rint x,rint tp) { d[x]=1,bl[x]=tp; q.push(x); while(!q.empty()) { rint x=q.front(); q.pop(); for(rint i=head[x];i;i=edge[i].nxt) { rint y=edge[i].to; if(!bar[y]&&!d[y]) { bl[y]=tp;d[y]=d[x]+1; q.push(y);f[y][0]=x; for(rint j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1]; } } } } int Lca(rint x,rint y) { if(d[x]>d[y]) swap(x,y); for(rint i=t;i>=0;i--) if(d[f[y][i]]>=d[x]) y=f[y][i]; if(x==y) return x; for(rint i=t;i>=0;i--) { if(f[y][i]^f[x][i]) { y=f[y][i]; x=f[x][i]; } } return f[x][0]; } void solve() { for(rint i=1;i<=n;i++) if(!bar[i]) get_dell(i,++dex); memset(bar,0,sizeof(bar)); for(rint i=1;i<=cnt;i++) for(rint j=0;j<dell[i].size();j++) bar[dell[i][j]]=1,l_a[dell[i][j]]=j,l_b[dell[i][j]]=i; for(rint i=1;i<=cnt;i++) for(rint j=0;j<dell[i].size();j++) bfs(dell[i][j],dell[i][j]); } int main() { n=read(),m=read(); t=log2(n)+1; for(rint i=1;i<=n;i++) fat[i]=i; for(rint i=1,x;i<=n;i++) { x=read(); add(x,i); fat[find(i)]=find(x); } solve(); for(rint i=1,x,y;i<=m;i++) { x=read(),y=read(); if(find(x)!=find(y)) printf("-1 -1\n"); else if(bl[x]==bl[y]) { rint lca=Lca(x,y); rint ll=d[x]-d[lca],rr=d[y]-d[lca]; printf("%d %d\n",ll,rr); } else { rint ll=abs(l_a[bl[x]]-l_a[bl[y]]),rr=dell[l_b[bl[x]]].size()-ll; rint edge=d[x]-d[bl[x]],r=d[y]-d[bl[y]]; rint ans1,ans2,ans3,ans4; if(l_a[bl[x]]<l_a[bl[y]]) ans1=edge+ll,ans2=r,ans3=edge,ans4=r+rr; else ans1=edge+rr,ans2=r,ans3=edge,ans4=r+ll; if(max(ans1,ans2)<max(ans3,ans4)) printf("%d %d\n",ans1,ans2); else if(max(ans1,ans2)>max(ans3,ans4)) printf("%d %d\n",ans3,ans4); else { if(min(ans1,ans2)<min(ans3,ans4)) printf("%d %d\n",ans1,ans2); else if(min(ans1,ans2)>min(ans3,ans4)) printf("%d %d\n",ans3,ans4); else printf("%d %d\n",max(ans1,ans2),min(ans1,ans2)); } } } return 0; }
放一下可怕的原码……(imcrazy这种变量名都出来了……)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int n,k,i_to[500005],tot_e,first[500005],first_q[500005],du[500005]; int low[500005],dfn[500005],cnt,tot_q,tot_f,first_f[500005]; int belong[500005],ac[500005][21],root,deep[500005]; int size_q[500005],size,cir,und[500005],b_tree[500005]; int c_point[500005]; int q_a,q_b; bool instack[500005],incir[500005],vis[500005];stack <int> s; struct node{int u,v,nxt;}edge[500005],edge_q[500005],edge_f[500005]; struct data{int belong,num;}point[500005]; inline void add(int uu,int vv) { ++tot_e; edge[tot_e].u=uu; edge[tot_e].v=vv; edge[tot_e].nxt=first[uu]; first[uu]=tot_e; } inline void add_q_f(int uu,int vv) { ++tot_f; edge_q[tot_f].u=uu;edge[tot_f].u=vv; edge_q[tot_f].v=vv;edge[tot_f].v=uu; edge_q[tot_f].nxt=first_q[uu]; edge_f[tot_f].nxt=first_f[vv]; first_q[uu]=tot_f;first_f[vv]=tot_f; } inline void tarjan(int x) { low[x]=dfn[x]=++cnt; s.push(x);instack[x]=true; for(rint i=first[x];i;i=edge[i].nxt) { int vv=edge[i].v; if(!dfn[vv]) { tarjan(vv); low[x]=min(low[vv],low[x]); } else if(instack[vv]) low[x]=min(dfn[vv],low[x]); } if(dfn[x]==low[x]) { ++tot_q; if(x==s.top()) { int l_point=s.top(); s.pop();instack[l_point]=false; belong[x]=tot_q; size_q[tot_q]++; } else { size=0; while(1) { int l_point=s.top(); s.pop();instack[l_point]=false; belong[l_point]=tot_q; point[l_point].belong=++cir; point[l_point].num=++size; incir[l_point]=1; size_q[tot_q]++; if(tot_q==x) break; } } } } inline void dfs(int x,int bel) { // cout<<"aa"<<endl; b_tree[x]=point[bel].belong; c_point[x]=bel; vis[x]=true; for(rint i=first[x];i;i=edge[i].nxt) { int vv=edge[i].v; if(vis[vv])continue; if(incir[vv]) dfs(vv,vv); else dfs(vv,bel); } } inline void bfs_f() { queue <int> q; q.push(root);deep[root]=1; while(!q.empty()) { int ll=q.front();q.pop(); for(rint i=first_f[ll];i;i=edge_f[i].nxt) { int vv=edge_f[i].v; if(deep[vv])continue; deep[vv]=deep[ll]+1; ac[vv][0]=ll; for(rint j=1;j<=20;++j) ac[vv][j]=ac[ac[vv][j-1]][j-1]; q.push(vv); } } } inline int lca(int xx,int yy) { if(deep[xx]>deep[yy])swap(xx,yy); for(rint i=20;i>=0;--i) if(deep[ac[yy][i]]>=deep[xx])yy=ac[yy][i]; if(xx==yy)return xx; for(rint i=20;i>=0;--i) if(ac[xx][i]!=ac[yy][i])xx=ac[xx][i],yy=ac[yy][i]; return ac[xx][0]; } int main() { scanf("%d %d",&n,&k); for(rint i=1;i<=n;++i) { scanf("%d",&i_to[i]); add(i,i_to[i]); } // cout<<"tarjan"<<endl; for(rint i=1;i<=n;++i) if(!dfn[i])tarjan(i); for(rint i=1;i<=n;++i) { if(belong[i_to[i]]==belong[i])continue; add_q_f(belong[i],belong[i_to[i]]); du[belong[i]]++; } // cout<<"dfs"<<endl; for(rint i=1;i<=n;++i) if(incir[i])dfs(i,i); for(rint i=1;i<=tot_q;++i) if(!du[i]){root=i;break;} // cout<<"bfs"<<endl; bfs_f(); for(rint i=1;i<=k;++i) { scanf("%d %d",&q_a,&q_b); if(b_tree[q_a]!=b_tree[q_b]) { cout<<"-1 -1"<<endl; continue; } else { if(belong[q_a]==belong[q_b]) { int imcrazy=abs(point[q_a].num-point[q_b].num); if(point[q_a].num>point[q_b].num) { imcrazy<(size_q[belong[q_a]]-imcrazy)?printf("0 %d\n",imcrazy):printf("%d 0\n",(size_q[belong[q_a]]-imcrazy)); continue; } else { imcrazy<(size_q[belong[q_a]]-imcrazy)?printf("%d 0\n",imcrazy):printf("0 %d\n",(size_q[belong[q_a]]-imcrazy)); continue; } } else if(incir[q_a]) printf("0 %d\n",(deep[q_b]+abs(point[c_point[q_b]].num-point[q_a].num))); else if(incir[q_b]) printf("%d 0\n",(deep[q_a]+abs(point[c_point[q_a]].num-point[q_b].num))); else { int Lca=lca(q_a,q_b); printf("%d %d\n",(deep[q_a]-deep[Lca]+1),(deep[q_b]-deep[Lca]+1)); } } } }
[图论]E.「太鼓达人」(二进制欧拉回路dfs)
恶心的东西。开始看不懂题,后来不会打。
问了利哥,结果他也不明白。我们一起理解题意,得到了starsing神的help,结果我先明白了给他讲的明白了。
码量很小但真的不好想。这是个屎啊。。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> using namespace std; int k,qyqyooo,ans[1<<13]; bool vis[(1<<13)+5]; inline bool dfs(int x,int len) { if(vis[x])return 0; if(len==(1<<k))return 1; ans[k+len-1]=x&1; int l=(x<<1),r=(x<<1)|1; vis[x]=1; if(dfs((x<<1)&qyqyooo,len+1)) return 1; if(dfs(((x<<1)|1)&qyqyooo,len+1)) return 1; vis[x]=0; return 0; } int main() { scanf("%d",&k); qyqyooo=(1<<k)-1; dfs(0,1); printf("%d ",qyqyooo+1); for(int i=1;i<=qyqyooo+1;i++) printf("%d",ans[i]); return 0; }
·随手记:
6:04:36
新的一天!loj不大友好。刚才听邻铺的lockey大佬说第三题是基环树。
那是啥……蒟蒻我不会啊QAQ。学习去QAQ。
14:00:20
太鼓达人等着我!
下午两个小时过掉太鼓达人咕咕咕!
16:07:29
咕咕咕时间刚刚好咩~A掉了太鼓达人。
接下来要苦战了。因为相对比较好做的题都做光了……退登博客园啦先。
过下一道题在上来。目标是物流运输。
17:58:37
之前又颓了
换了个目标,挑战自己,天天爱跑步(这道题A的人多)
大致了解了用啥知识去做。多谢BARCA大佬。
章·一:2019-07-11:昨夜西风凋碧树,独上高楼,望尽天涯路
·今日进度
[图论]B.「矩阵游戏」(二分图模板)
好多人问我……
以为说一下二分图你们就能秒懂……
写个题解。
行建点,列建点,黑格做边,匈牙利算法求最大匹配。
最后看最大匹配是否是完美匹配就odk。
顺便说一句:我没颓题解!
/* 警戒!警戒! 多判题目! 「抵制克苏恩」血的教训…… */ #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #define read(a) a=init() #define rint register int using namespace std; int T,n,map[203][203],cx[203],cy[203]; int sum0,ans=0; bool h=false,wr=false,vis[203]; inline int init() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+(ch-'0');ch=getchar();} return a*b; } inline bool find(int u) { for(register int i=1;i<=n;++i) if(map[u][i]&&!vis[i]) { vis[i]=true; if(cy[i]==-1||find(cy[i])) { cx[u]=i,cy[i]=u; return 1; } } return 0; } int main() { read(T); while(T--) { read(n);wr=false;ans=0; memset(cx,-1,sizeof(cx)); memset(cy,-1,sizeof(cy)); for(rint i=1;i<=n;++i) { h=false; for(rint j=1;j<=n;++j) { read(map[i][j]); if(map[i][j])sum0++,h=true; } if(!h)wr=true; } // cout<<sum0<<endl; if(sum0<n||wr){cout<<"No"<<endl;continue;} for(rint i=1;i<=n;++i) { h=false; for(rint j=1;j<=n;++j) if(map[j][i])h=true; if(!h)wr=true; } if(wr){cout<<"No"<<endl;continue;} for(rint i=1;i<=n;++i) { memset(vis,0,sizeof(vis)); ans+=find(i); } if(ans==n)cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
放一个匈牙利算法模板,转自https://blog.csdn.net/qq_40938077/article/details/80410356
int point(int u)//这个函数的作用是寻找增广路和更新cx,xy数组,如果找到了增广路,函数返回1,找不到,函数返回0。 { for(int v=1;v<=ny;v++)//依次遍历右边的所有顶点 { if(e[u][v]&&!visited[v])//条件一:左边的u顶点和右边的v顶点有连通边,条件二:右边的v顶点在没有被访问过,这两个条件必须同时满足 { visited[v]=1;//将v顶点标记为访问过的 if(cy[v]==-1||point(cy[v]))//条件一:右边的v顶点没有左边对应的匹配的点,条件二:以v顶点在左边的匹配点为起点能够找到一条增广路(如果能够到达条件二,说明v顶点在左边一定有对应的匹配点)。 { cx[u]=v;//更新cx,cy数组 cy[v]=u; return 1; } } } return 0;//如果程序到达了这里,说明对右边所有的顶点都访问完了,没有满足条件的。 }
[图论]A.「菜肴制作」(拓扑排序+大根堆)
倒序建边,跑拓扑序。
(为什么倒序?贪心策略错啦!你正序连样例第三组数据都跑不过。)
另外,多判一定要把所有参数全部清空。
多判不清空,爆零两行泪。(没清空tot我调了半小时……)
特判impossible比较奇诡。Larry点了一下我才想出来。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int T,n,m,a,b,tot,first[100003]; int du[100003]; struct node{ int u,v,nxt; }; bool pan=0,vis[100003]; inline void add(int uu,int vv,node edge[]) { ++tot; edge[tot].u=uu; edge[tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } int main() { scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); memset(vis,0,sizeof(vis)); memset(du,0,sizeof(du)); memset(first,0,sizeof(first)); tot=0; priority_queue <int> q; stack <int> s; node edge[100003]; for(rint i=1;i<=m;++i) { scanf("%d %d",&a,&b); add(b,a,edge);du[a]++; } for(rint i=1;i<=n;++i) { if(!du[i])q.push(i); vis[i]=1; } if(q.empty()){cout<<"Impossible!"<<endl;continue;} while(!q.empty()) { int xx=q.top();s.push(xx);q.pop(); // cout<<xx<<endl; pan=0; for(rint i=first[xx];i;i=edge[i].nxt) { int yy=edge[i].v; du[yy]--; if(!du[yy]) { pan=1; q.push(yy); // cout<<"yy"<<yy<<endl; vis[yy]=1; } } // if(pan==0&&q.empty()){cout<<"Impossible!"<<endl;break;} } // if(pan==0)continue; if(s.size()!=n){cout<<"Impossible!"<<endl;continue;} while(!s.empty()) { cout<<s.top()<<' '; s.pop(); } cout<<endl; } }
[图论]I.「软件安装」(tarjan缩点+神仙dp)
看完题我想到了某道ppt原题:很郁闷的金明。对着树形dp的ppt就是一顿yy。然后开始打。
打了半天dp一分没拿。我意识到有点不大对。
问了大佬说是有环,要跑一边tarjan缩点。我一阵猛缩,调了一下午,改了十多个参数(颓了题解),终于……80分。
崩溃了的我一边自嘲一边开大了数组,AC!wtf!
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int tot_e,cnt,n,m,w[202],v[202],d[202],dfn[202],low[202]; int tot_q,belong[202],qw[202],qv[202],first[202],deg[202]; int count[202],list[202],tpt=0,dp[202][505],first2[202],tot_e2; bool instack[202]; struct node{int u,v,nxt;}edge[202],edge2[202]; struct data{int fa,lc,rc;}tree[202]; stack <int> s; inline void add(int uu,int vv) { ++tot_e; edge[tot_e].u=uu; edge[tot_e].v=vv; edge[tot_e].nxt=first[uu]; first[uu]=tot_e; } inline void add2(int uu,int vv) { ++tot_e2; edge2[tot_e2].u=uu; edge2[tot_e2].v=vv; edge2[tot_e2].nxt=first2[uu]; first2[uu]=tot_e2; } inline void tarjan(int x) { dfn[x]=low[x]=++cnt; s.push(x);instack[x]=true; for(rint i=first[x];i;i=edge[i].nxt) { int y=edge[i].v; if(!dfn[y]) { tarjan(y); low[x]=min(low[y],low[x]); } else if(instack[y]) low[x]=min(dfn[y],low[x]); } if(dfn[x]==low[x]) { ++tot_q; while(1) { int lin=s.top(); s.pop();instack[lin]=false; belong[lin]=tot_q; qw[tot_q]+=w[lin];qv[tot_q]+=v[lin]; if(lin==x) break; } } } inline void dfs(int x) { for(rint i=first2[x];i;i=edge2[i].nxt) { int to=edge2[i].v; dfs(to); for(rint j=m;j>=0;--j) { for(rint p=0;p<=j;++p) dp[x][j]=max(dp[x][j],dp[to][p]+dp[x][j-p]); } } for(rint i=m;i>=0;--i) { if(i>=qw[x]) dp[x][i]=dp[x][i-qw[x]]+qv[x]; else dp[x][i]=0; } } int main() { scanf("%d %d",&n,&m); for(rint i=1;i<=n;++i)scanf("%d",&w[i]); for(rint i=1;i<=n;++i)scanf("%d",&v[i]); for(rint i=1;i<=n;++i) { scanf("%d",&d[i]); if(d[i]) add(d[i],i); } for(rint i=1;i<=n;++i) if(!dfn[i])tarjan(i); for(rint i=1;i<=n;++i) { if(!d[i]) continue; if(belong[i]==belong[d[i]]) continue; add2(belong[d[i]],belong[i]);deg[belong[i]]++; } /* for(rint x=1;x<=n;x++) { if(!d[x])continue; for(rint i=first[x];i;i=edge[i].nxt) { if(belong[x]==belong[edge[i].v])continue; add2(belong[x],belong[edge[i].v]); deg[belong[edge[i].v]]++; } } */ for(rint i=1;i<=tot_q;i++) if(!deg[i])add2(tot_q+1,i); dfs(tot_q+1); cout<<dp[tot_q+1][m]<<endl; return 0; }
[图论]D.「tree」(最小生成树+二分答案)
读完题和利哥讨论了一会儿没思路。找天皇问了一下,(我在天皇眼里看到了……无奈?)
天皇和萌巨佬争相吐槽说这道题有问题。代码诡异,标程都不对,还说他们颓了题解(此处省略一千字)
我晕头转向,回来就心安理得的颓了个题解,打了,一个小时,A了?传说中的诡异没有出现?
后悔颓题解了(得了便宜+买乖)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<algorithm> #define rint register int using namespace std; int n,m,need,l,r,cnt,tot,ans; int u[100005],v[100005],c[100005],col[100005]; int fa[100005]; struct node {int u,v,c,col;}edge[100005]; inline int read() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+(ch-'0');ch=getchar();} return a*b; } inline bool cmp(node a,node b){return a.c==b.c?a.col<b.col:a.c<b.c;} inline int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);} inline bool kruskal(int x) { int f1,f2,sum=0; for(rint i=1;i<=n;i++) fa[i]=i; for(rint i=1;i<=m;i++) { edge[i].u=u[i]; edge[i].v=v[i]; edge[i].c=c[i]; edge[i].col=col[i]; if(!col[i]) edge[i].c+=x; } sort(edge+1,edge+m+1,cmp); for(rint i=1;i<=m;i++) { f1=get(edge[i].u),f2=get(edge[i].v); if(f1!=f2) { fa[f1]=f2; sum++; tot+=edge[i].c; if(!edge[i].col) cnt++; } if(sum==n-1) if(cnt>=need)return 1; else return 0; } } int main() { n=read(),m=read(),need=read(); for(rint i=1;i<=m;i++) u[i]=read()+1,v[i]=read()+1,c[i]=read(),col[i]=read(); l=-101,r=101; while(l<r) { tot=cnt=0; int mid=(l+r)>>1; if(kruskal(mid)) l=mid+1,ans=tot-need*mid; else r=mid; } cout<<ans<<endl; return 0; }
·随手记
11:21
为了给我们压力,老师把山大附中的拉到了oj里。然后就展开了拉锯战。压力山大。(对面就是山大附中啊……)
不知道对面是不是以前打过这些题目。初期我们竟然失利了……前二被对方雄据。而且所有题居然都是1A!?怀疑对方颓了题解。
劳资不服!虽然弱,但我要刚上去!第一A了三道,我是两道。差一点啊啊。
我不颓题解,我认真。
11:45
NC哥夺回第一,NC哥威武!
完了我有点懈怠了……要吃饭了啊QAQ我要继续努力啊~
13:56
中午竟然有人没回宿舍午休……&……%¥#@我怎么没想到……
下午回来排行榜第一依旧是NC哥。过题数变成了四个。
同样变成四个的还有山大附中的一个人。无力感
继续努力。
15:19
山大附中都是什么人啊……在外网交付评测,攒够题目直接往oj上砸……
NC哥的rank1被半路杀出来的一个山大附中的夺走了。
这人五分钟A掉了五道题……他嗑药了么……
盘他!
19:04
我终于AC啦!!!垂死病中惊坐起,谈笑风生又一年!
调了一个下午,请了诸多大佬,挨了无数顿数落,查了许多题解我终于AC了!
(我打了三个多小时打错了才颓的代码能不能从轻处理……)
但是被大佬们落的好远啊……/一头撞死/生无可恋
继续努力!
21:07
又A掉了一道tree(水题?)Kruskal算法。
感觉今天复习了好多美妙图论算法,怪不得教练说这里面啥都有……
总结一下今天复习了:拓扑、二分图(增广路以及匈牙利算法)、树归、最小生成树(Kruskal)。
奇怪的是开专题以前一直以为占主要部分的最短路类题目竟然一道都没遇到??
今天还是有点颓废了。写的东西有点多啊……
序章:2019-07-10:愿乘长风破万里浪
明天开始集训咕咕咕~
我该怎么庆祝不考期末
距离noip还有四个月。我还是那么菜鸡。我好慌啊……
暑期好好补补。
约法三章
首先是绝对不能被干回去。大假期集训内容那么紧。被干回去以我的水平肯定完了。(不被干回去也够呛)
其次是尽量不颓废。之前集训的时候颓的太厉害导致水平低下……(说的好听做起来……)反正我会努力的,请机房诸位神佬监督。
第三是尽量不颓题解,坚决不颓代码(模板除外啊~蒟蒻弱弱地申辩)。
警戒·禁区
1.白天尽量不写详细题解颓废,到晚上择一天中有用的部分写详细题解。
2.不能过于颓废,不能出现重大违纪行为(比如某学长曾……(此处省略一千字简介))
3.禁止出现利用网络之便玩游戏、看小说行为。
继续去改0707的T2……今天只A掉了一道T3……
我好菜啊……