Codeforces Round #520 (Div. 2)
阿新 • • 發佈:2018-11-23
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(inti=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(intx,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); }