結果
| 問題 |
No.2892 Lime and Karin
|
| コンテスト | |
| ユーザー |
pockyny
|
| 提出日時 | 2025-06-30 07:45:43 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 234 ms / 8,000 ms |
| コード長 | 5,588 bytes |
| コンパイル時間 | 1,365 ms |
| コンパイル使用メモリ | 91,428 KB |
| 実行使用メモリ | 40,576 KB |
| 最終ジャッジ日時 | 2025-06-30 07:45:54 |
| 合計ジャッジ時間 | 10,943 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 52 |
ソースコード
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
ll INF = 1000000000000000000;
template<typename T = ll>
struct segment_tree{
int n; vector<T> seg;
T e(){return 0;}
T op(T a,T b){return (a + b);}
segment_tree(){}
segment_tree(int sz){n = sz; seg.resize(2*n,e());}
segment_tree(vector<T> v){
n = v.size(); seg.resize(2*n,e());
for(int i=0;i<n;i++) seg[i + n] = v[i];
for(int i=n - 1;i>0;i--) seg[i] = op(seg[i<<1],seg[i<<1|1]);
}
void init(int sz){n = sz; seg.resize(2*n);}
void update(int p,T val){
for(seg[p += n] += val;p>1;p>>=1) seg[p>>1] = op(seg[p],seg[p^1]);
}
T get(int p){return seg[p + n];}
T query(int l,int r){
T res = e();
for(l += n,r += n; l<r;l>>=1,r>>=1){
if(l&1) res = op(res,seg[l++]);
if(r&1) res = op(res,seg[--r]);
}
return res;
}
void clear(){for(int i=0;i<2*n;i++) seg[i] = e();}
};
#include <iostream>
#include <vector>
using namespace std;
// 参考: https://nyaannyaan.github.io/library/tree/dsu-on-tree.hpp.html
template <typename T = int>
struct DSUonTree {
vector<vector<T>> g;
vector<int> sz;
// 部分木クエリにeuler tourで答えるように、iの子要素を列挙する
vector<int> euler,up,down;
// eulerとかを途中で使う用のcount
int idx_;
// 根
int root;
// sub tree計算用
void dfs1(int cur, int par = -1){
sz[cur] = 1;
if ((int)g[cur].size() >= 2 && g[cur][0] == par) swap(g[cur][0], g[cur][1]);
for(T &v : g[cur]){
if (v == par) continue;
dfs1(v,cur);
sz[cur] += sz[v];
if (sz[v] > sz[g[cur][0]]) swap(v, g[cur][0]);
}
}
void dfs2(int cur, int par = -1) {
euler[idx_] = cur;
down[cur] = idx_++;
for(auto &v : g[cur]){
if (v == par) continue;
dfs2(v, cur);
}
up[cur] = idx_;
}
DSUonTree(vector<vector<T>> &_g,int _root = 0)
: g(_g),
sz(_g.size()),
euler(_g.size()),
up(_g.size()),
down(_g.size()),
idx_(0),
root(_root){
dfs1(root);
dfs2(root);
}
template <typename UPDATE, typename QUERY, typename CLEAR, typename RESET>
void run(UPDATE &update, QUERY &query, CLEAR &clear, RESET &reset) {
auto dfs_update = [&](auto rc,int cur,int par = -1) -> void {
update(cur);
for(int u:g[cur]){
if(u==par) continue;
rc(rc,u,cur);
}
return;
};
auto dfs_calc = [&](auto rc,int lca,int cur,int par = -1) -> void {
query(cur,lca);
for(int u:g[cur]){
if(u==par) continue;
rc(rc,lca,u,cur);
}
return;
};
auto dsu = [&](auto rc, int cur, int par = -1, bool keep = false) -> void {
for (int i = 1; i < (int)g[cur].size(); i++){
if (g[cur][i] != par) rc(rc, g[cur][i], cur, false);
}
if(sz[cur]!= 1) rc(rc, g[cur][0], cur, true);
if (sz[cur] != 1){
for(int i=1;i<g[cur].size();i++){
if(g[cur][i]==par) continue;
dfs_calc(dfs_calc,cur,g[cur][i],cur);
dfs_update(dfs_update,g[cur][i],cur);
}
}
update(cur);
query(cur,cur);
if (!keep){
for (int i = down[cur]; i < up[cur]; i++) clear(euler[i]);
reset();
}
return;
};
dsu(dsu, root);
}
};
int main(){
int i,n; cin >> n;
vector<vector<int>> g(n);
for(i=0;i<n - 1;i++){
int x,y; cin >> x >> y; x--; y--;
g[x].push_back(y); g[y].push_back(x);
}
string s; cin >> s;
vector<int> d(n);
auto dfs = [&](auto self,int cur,int par,int val) -> void {
if(s[cur]=='0') val--;
else val++;
d[cur] = val;
for(int u:g[cur]){
if(u==par) continue;
self(self,u,cur,val);
}
};
dfs(dfs,0,-1,0);
// [-n,n]
segment_tree seg(2*n + 1);
ll ans = 0;
// node iの中身をglobalなデータに反映する
auto update = [&](int i) {
seg.update(d[i] + n,1);
};
// iに対するクエリに答える
auto query = [&](int i,int lca){
ll cost = (s[lca]=='1') ? 1 : -1;
// d[v] > -d[i] + d[lca] - cost なるvの数
ll le = max(0LL,-d[i] + 2*d[lca] - cost + n + 1);
ans += seg.query(le,2*n + 1);
// cout << "query == " << i + 1 << " " << lca + 1 << " " << seg.query(le,2*n + 1) << "\n";
// cout << "range == " << -d[i] + d[lca] - cost << "\n";
// for(int j=0;j<=2*n;j++) cout << seg.get(j) << " ";
// cout << "\n";
};
// seg木とかの場合、一気にresetするのが難しいのでこっちで頂点ごとにclearする
auto clear = [&](int i) {
seg.update(d[i] + n,-1);
};
// データ構造を空にする
auto reset = [&]() {};
DSUonTree<> ds(g);
ds.run(update,query,clear,reset);
cout << ans << "\n";
// for(i=0;i<=2*n;i++) cout << seg.get(i) << " ";
// cout << "\n";
// for(i=0;i<n;i++) cout << d[i] << " ";
// cout << "\n";
// for(i=0;i<n;i++){
// cout << i + 1 << " ";
// for(int u:ds.g[i]) cout << u + 1 << " ";
// cout << "\n";
// }
}
pockyny