제출 #109653

#제출 시각아이디문제언어결과실행 시간메모리
109653user202729철인 이종 경기 (APIO18_duathlon)C++17
100 / 100
277 ms31560 KiB
// https://oj.uz/problem/view/APIO18_duathlon #include<iostream> #include<vector> #include<cassert> std::vector<std::vector<int>> adjl; int nnode; int lastnum=0; std::vector<int> dnum,dlow; std::vector<int> stk; // adjlist for circle-square-tree // node with index < nnode are real std::vector<std::vector<int>> cst_adjl; int64_t ans; void dfs(int node,int par){ assert(dnum[node]==0); dnum[node]=dlow[node]=++lastnum; stk.push_back(node); for(int ad:adjl[node]){ if(ad==par)continue; if(dnum[ad]) dlow[node]=std::min(dlow[node],dnum[ad]); else{ // ad is a child of node dfs(ad,node); if(dlow[ad]>=dnum[node]){ // it creates a new biconnected component auto iter=--stk.end(); while(*iter!=ad)--iter; std::vector<int> v; v.reserve(stk.end()-iter+1); v.assign(iter,stk.end()); v.push_back(node); int newnode=(int)cst_adjl.size(); assert(newnode>=nnode); for(int x:v) cst_adjl[x].push_back(newnode); cst_adjl.push_back(std::move(v)); stk.erase(iter,stk.end()); }else{ dlow[node]=std::min(dlow[node],dlow[ad]); } } } } std::vector<int> cst_par, cst_stsize /* only includes real nodes */; void dfs2(int node){ int& cst_stsize_node=cst_stsize[node]; assert(cst_stsize_node==0); cst_stsize_node=node<nnode; for(int adj:cst_adjl[node])if(adj!=cst_par[node]){ cst_par[adj]=node; dfs2(adj); cst_stsize_node+=cst_stsize[adj]; } assert(cst_stsize_node>0); } std::vector<int64_t> ssqr; int64_t sqr(int x){return (int64_t)x*x;} int ccsize; // size of currently considering connected component, in real nodes void dfs3(int node){ if(node<nnode){ // consider c == node. how many of (s,t) pairs are over-counted? for(int d:cst_adjl[node]){ // assume s and t are "to the direction of d" from c assert(d>=nnode&&cst_adjl[d].size()>1); int64_t& ssqr_d=ssqr[d-nnode]; if(ssqr_d==0){ // compute ssqr_d first assert(d!=cst_par[node]); for(int x:cst_adjl[d]) if(cst_par[d]==x) ssqr_d+=sqr(ccsize-cst_stsize[d]); else ssqr_d+=sqr(cst_stsize[x]); assert(ssqr_d!=0); ans-=ssqr_d; ans+=sqr(ccsize-cst_stsize[d]); }else{ assert(d==cst_par[node]); ans-=ssqr_d; ans+=sqr(cst_stsize[node]); } } } for(int adj:cst_adjl[node])if(adj!=cst_par[node]){ dfs3(adj); } } int main(){ std::ios::sync_with_stdio(0);std::cin.tie(0); int nedge;std::cin>>nnode>>nedge; adjl.resize(nnode); for(int i=nedge;i-->0;){ int u,v;std::cin>>u>>v; --u;--v; adjl[u].push_back(v); adjl[v].push_back(u); } dnum.resize(nnode); dlow.resize(nnode); ans=0; cst_adjl.resize(nnode); std::vector<int> fnodes; // each connected component has exactly one fnode for(int node=0;node<nnode;++node)if(dnum[node]==0){ fnodes.push_back(node); assert(stk.empty()); dfs(node,-1); assert(stk.size()==1&&stk[0]==node); stk.clear(); } cst_par.assign(cst_adjl.size(),-1); cst_stsize.resize(cst_adjl.size()); ssqr.resize(cst_adjl.size()-nnode); for(int x:fnodes){ assert(x<nnode); dfs2(x); ccsize=cst_stsize[x]; ans+=ccsize // for each way to choose vertex c *(ccsize-1LL)*(ccsize-1); // there are at most % ways to choose s and t // (allow them to overlap but not the same as c) dfs3(x); } std::cout<<ans<<'\n'; } /* 4 3 1 2 2 3 3 4 4 4 1 2 2 3 3 4 4 2 5 6 1 2 1 3 2 3 2 4 2 5 4 5 */
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...