Codeforces Round #520 (Div. 2)
D. Fun with Integers
题意:
给你一个n,对于任意的 2≤|a|,|b|≤n ,如果存在一个整数x,使得 $a*x=b$ 或者 $b*x=a$ ,那么a向b连一条边权为|x|的边。
问不经过重复的边最长的一条路径的长度。
思路:
我们发现这张图有欧拉回路,然后就把所有边权加起来就好了2333333
//By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long long int n,ans; signed main(){ scanf("%lld",&n); for(int i=2;i<=n;i++) for(int j=i*2;j<=n;j+=i) ans+=j/i; printf("%lld\n",ans*4); }
E. Company
题意:
给你一个含n个点的有根树,q次询问,每次问[l,r]区间中删掉任何一个点,使得所有点的deep[LCA]最大,问删掉的点是哪个,深度最大是多少。SPJ
思路:
我们可以发现,一段区间的LCA也就是dfs序最小的点和dfs序最大的点的lca。
那我们可以枚举删除的是dfs序最小的那个点还是dfs序最大的那个点。
具体来说就是线段树维护区间dfs序的最小值,次小值,最大值,次大值。每回询问的时候查询一下lca就好了
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=200050; int n,q,fa[N][20],v[N],nxt[N],first[N],tot,dfn[N],rev[N],cnt,deep[N]; int maxx[N<<2],max2[N<<2],minn[N<<2],min2[N<<2]; void add(int x,int y){ v[tot]=y,nxt[tot]=first[x],first[x]=tot++; } void dfs(int x){ dfn[x]=++cnt,rev[cnt]=x; for(int i=1;i<20;i++)fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=first[x];~i;i=nxt[i]) deep[v[i]]=deep[x]+1,dfs(v[i]); } void push_up(int pos){ int lson=pos<<1,rson=pos<<1|1,tmp[4]; tmp[0]=maxx[lson],tmp[1]=max2[lson]; tmp[2]=maxx[rson],tmp[3]=max2[rson]; sort(tmp,tmp+4); maxx[pos]=tmp[3],max2[pos]=tmp[2]; tmp[0]=minn[lson],tmp[1]=min2[lson]; tmp[2]=minn[rson],tmp[3]=min2[rson]; sort(tmp,tmp+4); minn[pos]=tmp[0],min2[pos]=tmp[1]; } void build(int l,int r,int pos){ if(l==r){ maxx[pos]=minn[pos]=dfn[l]; min2[pos]=N; return; } int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; build(l,mid,lson),build(mid+1,r,rson); push_up(pos); } pair<int,int> query_max(int l,int r,int pos,int L,int R){ if(l>=L&&r<=R)return make_pair(maxx[pos],max2[pos]); int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<L)return query_max(mid+1,r,rson,L,R); else if(mid>=R)return query_max(l,mid,lson,L,R); else{ pair<int,int>t=query_max(l,mid,lson,L,R); pair<int,int>t2=query_max(mid+1,r,rson,L,R); int tmp[4]; tmp[0]=t.first,tmp[1]=t.second; tmp[2]=t2.first,tmp[3]=t2.second; sort(tmp,tmp+4); return make_pair(tmp[3],tmp[2]); } } pair<int,int> query_min(int l,int r,int pos,int L,int R){ if(l>=L&&r<=R)return make_pair(minn[pos],min2[pos]); int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<L)return query_min(mid+1,r,rson,L,R); else if(mid>=R)return query_min(l,mid,lson,L,R); else{ pair<int,int>t=query_min(l,mid,lson,L,R); pair<int,int>t2=query_min(mid+1,r,rson,L,R); int tmp[4]; tmp[0]=t.first,tmp[1]=t.second; tmp[2]=t2.first,tmp[3]=t2.second; sort(tmp,tmp+4); return make_pair(tmp[0],tmp[1]); } } int lca(int x,int y){ if(x<1||x>n)return -1; if(deep[x]<deep[y])swap(x,y); for(int i=19;~i;i--)if(deep[fa[x][i]]>=deep[y])x=fa[x][i]; if(x==y)return x; for(int i=19;~i;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main(){ memset(first,-1,sizeof(first)); scanf("%d%d",&n,&q); for(int i=2;i<=n;i++)scanf("%d",&fa[i][0]),add(fa[i][0],i); dfs(1);build(1,n,1); while(q--){ int xx,yy; scanf("%d%d",&xx,&yy); pair<int,int>mx=query_max(1,n,1,xx,yy); pair<int,int>mn=query_min(1,n,1,xx,yy); int t1=lca(rev[mx.first],rev[mn.second]); int t2=lca(rev[mx.second],rev[mn.first]); if(deep[t1]>=deep[t2])printf("%d %d\n",rev[mn.first],deep[t1]); else printf("%d %d\n",rev[mx.first],deep[t2]); } }
F.
题意:
给你一个DAG。
对于每个点,我们需要统计两个量:
从它出发能到的点的数量a
从其它点出发能到达它的点的数量b
如果a+b=n-2,那么这个点是好的
问这张图里有多少个好的点
思路:
一开始没有思路,参考了题解
我们可以拓扑排序一下,有三种情况
1.拓扑排序的过程中队列大小为0,也就是只有一条链,那么这个点贡献+=还没有进入队列的所有点
2.如果队列大小为1,也就是有两条链,这个时候需要判断一下另一个点所到达的所有点的入读是不是都>1,如果有不是的,那么就不管。
如果都>1,当前点贡献+=还没有进入队列的点
3.如果队列大小>1,那么这个点不可能满足条件
反向建图再来一遍
如果两次贡献和+2>=n,那么这个点是好的
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=600050; int n,m,fm[N],to[N],in[N],all,ans[N],e; vector<int>g[N];queue<int>q; void topsort(int *u,int *v){ memset(in,0,sizeof(in)),all=n; for(int i=1;i<=n;i++)g[i].clear(); while(!q.empty())q.pop(); for(int i=1;i<=m;i++)g[u[i]].push_back(v[i]),in[v[i]]++; for(int i=1;i<=n;i++)if(!in[i])q.push(i),all--; while(!q.empty()){ int t=q.front();q.pop(); if(q.empty())ans[t]+=all; else if(q.size()==1){ bool flg=1; for(auto i:g[q.front()])flg&=(in[i]>1); ans[t]+=flg*all; } else ans[t]=-N; for(auto i:g[t])if(!(--in[i]))q.push(i),all--; } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d%d",&fm[i],&to[i]); topsort(fm,to),topsort(to,fm); for(int i=1;i<=n;i++)if(ans[i]+2>=n)e++; printf("%d\n",e); }