#include #include using namespace std; struct UF{ vector par,sz; // 連結成分の親 vector cp_par; vector> mergeTree; UF(int n, bool useMergeTree = false){ sz.resize(n); par.resize(n); cp_par.resize(n); for(int i=0;isz[y]) swap(x,y); sz[y] += sz[x]; par[x] = y; cp_par[y] = same(cp_par[y],y) ? cp_par[x] : cp_par[y]; } bool same(int x,int y){return find(x)==find(y);} void merge(int child,int parent){ //parentが親,merge過程を表す木などで使用 child = find(child); parent = find(parent); if(child==parent) return; mergeTree[parent].push_back(child); sz[parent] += sz[child]; par[child] = parent; } }; #include #include #include using namespace std; typedef long long ll; typedef pair pll; typedef pair pllll; const int SZ = 200000; // 問題ごとに必要なものを実装 ll val[SZ + 10],cnt[SZ + 10],ans[SZ + 10]; struct Cmp{ bool operator()(const pllll &l,const pllll &r){ // cout << l.first.first << "/" << l.first.second << "," << r.first.first << "/" << r.first.second << endl; return l.first.first * r.first.second < l.first.second * r.first.first; } }; // idとidの親をmergeして、新しい代表の値を返す // 問題ごとに実装する int merge(int id,UF &uf){ id = uf.find(id); int pa = uf.find(uf.cp_par[id]); ll nv = val[pa] + val[id],nc = cnt[pa] + cnt[id]; ll nans = ans[pa] + ans[id] + cnt[pa]*val[id]; uf.unite(id,pa); int n_id = uf.find(id); val[n_id] = nv; cnt[n_id] = nc; ans[n_id] = nans; return n_id; } // 01OnTreeを解く // input: p,a. pは根を0として、0-nの親の配列 (p[0] = -1;) // output 根から順にtopological順序で、0-nを割りふってΣi*a[i]の最小化 ll TreeTopoMin(vector &p, vector &a){ int i,n = p.size(); UF uf(n); for(i=1;i,Cmp> que; int t = 0; // queに入れたものの有効無効の判定に使う vector tm_stamp(n); auto custom_push = [&](int id){ que.push({{val[id],cnt[id]},{uf.find(id),t}}); tm_stamp[uf.find(id)] = t; t++; }; for(i=1;i> n; string s; cin >> s; vector p(n + 1),a(n + 1); for(i=1;i<=n;i++) cin >> a[i]; int now = 0,mx = 0; p[0] = -1; for(char c:s){ if(c=='('){ mx++; p[mx] = now; now = mx; }else{ now = p[now]; } } cout << TreeTopoMin(p,a) << "\n"; }