1. 程式人生 > >Codeforces Round #520 (Div. 2)

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);
}