結果
| 問題 |
No.3193 Submit Your Solution
|
| コンテスト | |
| ユーザー |
Rubikun
|
| 提出日時 | 2025-06-28 03:04:31 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 4,352 ms / 10,000 ms |
| コード長 | 9,570 bytes |
| コンパイル時間 | 3,077 ms |
| コンパイル使用メモリ | 230,296 KB |
| 実行使用メモリ | 294,972 KB |
| 最終ジャッジ日時 | 2025-06-28 03:05:42 |
| 合計ジャッジ時間 | 56,756 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 17 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define vi vector<int>
#define vl vector<ll>
#define vii vector<pair<int,int>>
#define vll vector<pair<ll,ll>>
#define vvi vector<vector<int>>
#define vvl vector<vector<ll>>
#define vvii vector<vector<pair<int,int>>>
#define vvll vector<vector<pair<ll,ll>>>
#define vst vector<string>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define mkunique(x) sort(all(x));(x).erase(unique(all(x)),(x).end())
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=200005,INF=15<<26;
vector<int> G2[MAX];
int vs[MAX*2];
int depth[MAX*2];
int id[MAX];
void dfs(int v,int p,int d,int &k){
id[v]=k;
vs[k]=v;
depth[k++]=d;
for(int to:G2[v]){
if(to==p) continue;
dfs(to,v,d+1,k);
vs[k]=v;
depth[k++]=d;
}
//cout<<k<<" ";
}
void init(){
int k=0;
dfs(0,-1,0,k);
}
struct SparseTable{
using T=int;
//using F=function<T(T,T)>;
int n,logn;
vector<vector<T>> dat;
vector<int> loglen;
vector<int> depthsv;
SparseTable(int n_){
n=1;
logn=1;
while(n<n_){
n*=2;
logn++;
}
loglen.resize(n+3);
depthsv.resize(n+3,INF);
n=n_;
int j=0;
for(int i=1;i<n+3;i++){
loglen[i]=j;
if(i+1>(1<<(j+1))) j++;
}
dat.resize(logn);
for(int i=0;i<logn;i++){
dat[i].assign(n+1,n+2);
}
}
void set(int j,pair<int,int> x){
auto [d,id]=x;
dat[0][j]=id;
depthsv[id]=d;
}
void built(){
for(int i=1;i<logn;i++){
for(int j=0;j<n+1;j++){
T vla=dat[i-1][j],vr;
if(j+(1<<(i-1))>=n+1) vr=n+2;
else vr=dat[i-1][j+(1<<(i-1))];
if(depthsv[vla]<depthsv[vr]) dat[i][j]=vla;
else dat[i][j]=vr;
}
}
}
int query(int l,int r){
if(l>=r){
return -1;
}else{
T vla=dat[loglen[r-l]][l],vr=dat[loglen[r-l]][r-(1<<loglen[r-l])];
if(depthsv[vla]<depthsv[vr]){
return vla;
}else{
return vr;
}
}
}
};
SparseTable spa(1);
int lca(int a,int b){
return spa.query(min(id[a],id[b]),max(id[a],id[b])+1);
}
int dd(int a,int b){
return depth[id[a]]+depth[id[b]]-2*depth[id[lca(a,b)]];
}
ll ans=0;
//auxiliary-tree
// https://beet-aizu.github.io/library/tree/auxiliarytree.cpp.html
struct LowestCommonAncestor{
int h;
vector< vector<int> > G,par;
vector<int> dep;
LowestCommonAncestor(int n):G(n),dep(n){
h=1;
while((1<<h)<=n) h++;
par.assign(h,vector<int>(n,-1));
}
void add_edge(int u,int v){
G[u].emplace_back(v);
G[v].emplace_back(u);
}
void dfs(int v,int p,int d){
par[0][v]=p;
dep[v]=d;
for(int u:G[v])
if(u!=p) dfs(u,v,d+1);
}
void build(int r=0){
int n=G.size();
dfs(r,-1,0);
for(int k=0;k+1<h;k++)
for(int v=0;v<n;v++)
if(~par[k][v])
par[k+1][v]=par[k][par[k][v]];
}
};
struct AuxiliaryTree : LowestCommonAncestor{
using super = LowestCommonAncestor;
vector<int> idx;
vl cn,omo,dp;
vvll T;
AuxiliaryTree(int n):super(n),idx(n),cn(n),omo(n),dp(n),T(n){}
void dfs(int v,int p,int &pos){
idx[v]=pos++;
for(int u:G[v])
if(u!=p) dfs(u,v,pos);
}
void build(int r=0){
super::build(r);
int pos=0;
dfs(r,-1,pos);
}
void add_aux_edge(int u,int v){
int d=dd(u,v);
T[u].emplace_back(mp(v,d));
T[v].emplace_back(mp(u,d));
}
using super::dep;
void query(vector<int> &vs){
/*
assert(!vs.empty());
sort(vs.begin(),vs.end(),
[&](int a,int b){return idx[a]<idx[b];});
vs.erase(unique(vs.begin(),vs.end()),vs.end());
*/
int k=vs.size();
vi st;
st.reserve(2*k-1);
st.pb(vs[0]);
for(int i=0;i+1<k;i++){
int w=lca(vs[i],vs[i+1]);
if(w!=vs[i]){
int l=st.back();st.pop_back();
while(!st.empty() and dep[w]<dep[st.back()]){
add_aux_edge(st.back(),l);
l=st.back();st.pop_back();
}
if(st.empty() or st.back()!=w){
st.pb(w);
vs.emplace_back(w);
}
add_aux_edge(w,l);
}
st.pb(vs[i+1]);
}
while(st.size()>1){
int c=st.back();st.pop_back();
add_aux_edge(st.back(),c);
}
}
void make(int u,int p){
for(auto [to,dd]:T[u]){
if(to==p) continue;
make(to,u);
dp[u]+=dp[to];
dp[u]+=cn[to]*dd;
cn[u]+=cn[to];
}
}
void solve(int u,int p){
dp[u]=0;
for(auto [to,dd]:T[u]){
dp[u]+=dp[to];
dp[u]+=cn[to]*dd;
}
ans+=dp[u]*omo[u];
//cout<<u<<" "<<dp[u]<<" "<<cn[u]<<" "<<omo[u]<<endl;
for(auto [to,dd]:T[u]){
if(to==p) continue;
ll a=dp[u],b=cn[u],c=dp[to],d=cn[to];
dp[u]-=dp[to];
dp[u]-=cn[to]*dd;
cn[u]-=cn[to];
cn[to]+=cn[u];
solve(to,u);
dp[u]=a;
cn[u]=b;
dp[to]=c;
cn[to]=d;
}
}
void clear(const vector<int> &ws){
for(int w:ws){
cn[w]=0;
omo[w]=0;
dp[w]=0;
T[w].clear();
}
}
};
AuxiliaryTree AT(1);
//重心分解(使える版)
int N,C=-1;
vi G[MAX];
bool centroid[MAX];
int subtree_size[MAX];
int centpar[MAX];
int compute_subtree_size(int u,int p){
int c=1;
for(int a:G[u]){
if(a==p||centroid[a]) continue;
c+=compute_subtree_size(a,u);
}
return subtree_size[u]=c;
}
pair<int,int> search_centroid(int u,int p,int t){
pair<int,int> res={INF,-1};
int s=1,m=0;
for(int a:G[u]){
if(a==p||centroid[a]) continue;
res=min(res,search_centroid(a,u,t));
m=max(m,subtree_size[a]);
s+=subtree_size[a];
}
m=max(m,t-s);
res=min(res,{m,u});
return res;
}
void atume(int u,int p,int d,vii &T){
T.pb(mp(d,u));
for(int to:G[u]){
if(to==p||centroid[to]) continue;
atume(to,u,d+1,T);
}
}
vi use;
vvii Y;
int keii[MAX*40];
int tim;
array<int,3> pos[MAX][40];
int poscur[MAX];
void calc(vii S,int kei){
if(si(S)<=1) return;
for(int j=0;j<si(S);j++){
auto [a,b]=S[j];
pos[AT.idx[b]][poscur[AT.idx[b]]++]={tim,a,b};
//pos[AT.idx[b]].pb({tim,a,b});
}
keii[tim]=kei;
tim++;
return;
}
void solve_subproblem(int u,int p){
compute_subtree_size(u,-1);
int s=search_centroid(u,-1,subtree_size[u]).second;
centroid[s]=1;
if(C==-1) C=s;
centpar[s]=p;
vii S;
//S.reserve(subtree_size[s]);
S.pb(mp(0,s));
for(int a:G[s]){
if(centroid[a]){
continue;
}
vii T;
//T.reserve(subtree_size[a]);
atume(a,s,1,T);
solve_subproblem(a,s);
calc(T,-1);
for(auto x:T) S.pb(x);
}
calc(S,1);
centroid[s]=0;
}
void solve(){
Y.resize(tim);
vi CNY(tim);
for(int i=0;i<N;i++){
for(int j=0;j<poscur[i];j++){
auto [t,a,b]=pos[i][j];
CNY[t]++;
}
}
for(int i=0;i<tim;i++){
Y[i].reserve(CNY[i]);
}
for(int i=0;i<N;i++){
for(int j=0;j<poscur[i];j++){
auto [t,a,b]=pos[i][j];
Y[t].pb(mp(a,b));
}
}
for(int i=0;i<si(Y);i++){
auto S=Y[i];
int kei=keii[i];
vi use(si(S));
for(int j=0;j<si(S);j++) use[j]=S[j].se;
AT.query(use);
for(auto [a,b]:S){
AT.omo[b]=a*kei;
AT.cn[b]=1;
}
AT.make(use[0],-1);
AT.solve(use[0],-1);
for(int x:use){
AT.dp[x]=0;
AT.omo[x]=0;
AT.cn[x]=0;
}
AT.clear(use);
}
}
int main(){
std::ifstream in("text.txt");
std::cin.rdbuf(in.rdbuf());
cin.tie(0);
ios::sync_with_stdio(false);
cin>>N;
for(int i=0;i<N-1;i++){
int a,b;cin>>a>>b;
a--;b--;
G[a].pb(b);
G[b].pb(a);
}
AT=AuxiliaryTree(N);
for(int i=0;i<N-1;i++){
int a,b;cin>>a>>b;
a--;b--;
G2[a].pb(b);
G2[b].pb(a);
AT.add_edge(a,b);
}
AT.build();
init();
spa=SparseTable(2*N-1);
for(int i=0;i<2*N-1;i++){
spa.set(i,mp(depth[i],vs[i]));
}
spa.built();
solve_subproblem(0,-1);
solve();
ans*=2;
cout<<ans<<endl;
}
Rubikun