結果
問題 | No.1038 TreeAddQuery |
ユーザー | chocorusk |
提出日時 | 2020-04-25 00:12:04 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 2,681 ms / 4,000 ms |
コード長 | 6,726 bytes |
コンパイル時間 | 2,086 ms |
コンパイル使用メモリ | 164,608 KB |
実行使用メモリ | 106,408 KB |
最終ジャッジ日時 | 2024-05-03 23:18:05 |
合計ジャッジ時間 | 33,589 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 3 ms
7,168 KB |
testcase_01 | AC | 3 ms
7,168 KB |
testcase_02 | AC | 3 ms
7,296 KB |
testcase_03 | AC | 14 ms
8,448 KB |
testcase_04 | AC | 18 ms
8,448 KB |
testcase_05 | AC | 16 ms
8,832 KB |
testcase_06 | AC | 13 ms
8,448 KB |
testcase_07 | AC | 18 ms
8,704 KB |
testcase_08 | AC | 1,483 ms
71,940 KB |
testcase_09 | AC | 1,714 ms
75,144 KB |
testcase_10 | AC | 1,748 ms
75,768 KB |
testcase_11 | AC | 1,854 ms
75,816 KB |
testcase_12 | AC | 1,850 ms
76,464 KB |
testcase_13 | AC | 2,681 ms
106,292 KB |
testcase_14 | AC | 2,334 ms
86,876 KB |
testcase_15 | AC | 2,240 ms
83,628 KB |
testcase_16 | AC | 2,195 ms
82,156 KB |
testcase_17 | AC | 2,112 ms
81,068 KB |
testcase_18 | AC | 325 ms
55,812 KB |
testcase_19 | AC | 413 ms
57,584 KB |
testcase_20 | AC | 370 ms
57,888 KB |
testcase_21 | AC | 473 ms
59,588 KB |
testcase_22 | AC | 732 ms
63,480 KB |
testcase_23 | AC | 832 ms
64,180 KB |
testcase_24 | AC | 1,349 ms
72,120 KB |
testcase_25 | AC | 2,540 ms
106,408 KB |
testcase_26 | AC | 1,369 ms
81,676 KB |
ソースコード
#include <cstdio> #include <cstring> #include <iostream> #include <string> #include <cmath> #include <bitset> #include <vector> #include <map> #include <set> #include <queue> #include <deque> #include <algorithm> #include <complex> #include <unordered_map> #include <unordered_set> #include <random> #include <cassert> #include <fstream> #include <utility> #include <functional> #include <time.h> #include <stack> #include <array> #define popcount __builtin_popcount using namespace std; typedef long long int ll; typedef pair<int, int> P; const int MAX_V = 100010; // ツリーのサイズのありうる最大値 int N; // ツリーのサイズ vector<vector<int>> tree; // ツリーを隣接リスト形式のグラフ構造で表したもの int sizeSubtree[MAX_V]; // sizeSubtree[v] := v を根とする部分ツリーのサイズ (分割統治の毎ステップごとに再利用) bool isRemoved[MAX_V]; // isRemoved[v] := v が既に取り除かれたかどうか int whoIsParent[MAX_V]; // whoIsParent[v] := ツリーDP時に v の親が誰だったか // メイン処理 vector<int> centroids; void FindCentroidRecursive(int v, int size, int p = -1) { sizeSubtree[v] = 1; whoIsParent[v] = p; bool isCentroid = true; for (auto ch : tree[v]) { if (ch == p) continue; if (isRemoved[ch]) continue; FindCentroidRecursive(ch, size, v); if (sizeSubtree[ch] > size / 2) isCentroid = false; sizeSubtree[v] += sizeSubtree[ch]; } if (size - sizeSubtree[v] > size / 2) isCentroid = false; if (isCentroid) centroids.push_back(v); } // 初期化 void Init() { for (int i = 0; i < MAX_V; ++i) { isRemoved[i] = false; } } // first: 重心, second: (重心の子ノード, 子部分木のサイズ) からなるベクトル pair<int, vector<pair<int,int> > > FindCentroid(int root, int size) { vector<pair<int, int> > subtrees; centroids.clear(); FindCentroidRecursive(root, size); int center = centroids[0]; for (auto ch : tree[center]) { if (isRemoved[ch]) continue; if (ch == whoIsParent[center]) { subtrees.push_back(make_pair(ch, size - sizeSubtree[center])); } else { subtrees.push_back(make_pair(ch, sizeSubtree[ch])); } } return make_pair(center, subtrees); } int par[100010]; vector<P> vd[100010]; int dist[100010]; void dfs(int v, int p, int cent){ whoIsParent[v] = p; vd[cent].push_back({v, dist[v]}); for(auto ch:tree[v]){ if (ch == p) continue; if (isRemoved[ch]) continue; dist[ch]=dist[v]+1; dfs(ch, v, cent); } } map<P, int> ind; int id; vector<vector<P>> vdc; int pc[100010]; void dfs1(int v, int p, int cent){ vdc[cent].push_back({v, dist[v]}); for(auto ch:tree[v]){ if (ch == p) continue; if (isRemoved[ch]) continue; dist[ch]=dist[v]+1; dfs1(ch, v, cent); } } void myon(int root, int size, int p=-1){ if(size<=1){ par[root]=p; if(p!=-1) pc[root]=root; else pc[root]=-1; vd[root].push_back({root, 0}); return; } auto pr=FindCentroid(root, size); int cent=pr.first; if(p!=-1) pc[cent]=root; else pc[cent]=-1; dist[cent]=0; dfs(cent, -1, cent); par[cent]=p; isRemoved[cent]=1; for(auto prr:pr.second){ if(!isRemoved[prr.first]){ dist[prr.first]=0; ind[{cent, prr.first}]=id; vector<P> nw; vdc.push_back(nw); dfs1(prr.first, -1, id); id++; myon(prr.first, prr.second, cent); } } } struct LCA{ vector<vector<int>> g; vector<int> d; vector<vector<int>> p; int log; int n; LCA(const vector<vector<int>> &g):g(g), d(g.size()), n(g.size()){ log=0; while(1<<log<=n) log++; p.resize(log, vector<int>(n)); } void dfs(int x, int prev){ for(auto y:g[x]){ if(y==prev) continue; d[y]=d[x]+1; p[0][y]=x; dfs(y, x); } } void build(){ dfs(0, -1); for(int i=1; i<log; i++){ for(int j=0; j<n; j++){ p[i][j]=p[i-1][p[i-1][j]]; } } } int lca(int a, int b){ if(d[a]>d[b]) swap(a, b); int dd=d[b]-d[a], i=0; int a1=a, b1=b; while(dd){ if(dd&1) b1=p[i][b1]; dd>>=1; i++; } if(a1==b1) return a1; for(int j=log-1; j>=0; j--){ if(p[j][a1]!=p[j][b1]){ a1=p[j][a1], b1=p[j][b1]; } } return p[0][a1]; } int dist(int a, int b){ return d[a]+d[b]-2*d[lca(a, b)]; } }; template<typename T> struct BIT{ vector<T> bit; int size; BIT(){} BIT(int n):size(n), bit(n+1, 0){} void init(int n){ size=n; bit.resize(n+1); } T sum(int i){ //[0, i) T s=0; while(i>0){ s+=bit[i]; i-=(i&(-i)); } return s; } T sum(int l, int r){ //[l, r) return sum(r)-sum(l); } void add(int i, T x){ i++; while(i<=size){ bit[i]+=x; i+=(i&(-i)); } } }; template<typename T> struct RangeAddPointGet{ BIT<T> bit; RangeAddPointGet(){} RangeAddPointGet(int n):bit(n){} void init(int n){ bit.init(n); } void add(int l, int r, T x){ bit.add(l, x); bit.add(r, -x); } T get(int i){ return bit.sum(i+1); } }; int main() { int n, q; cin>>n>>q; tree.resize(n); for(int i=0; i<n-1; i++){ int a, b; scanf("%d %d", &a, &b); a--; b--; tree[a].push_back(b); tree[b].push_back(a); } myon(0, n); int mx[100010]={}, mxc[200020]={}; for(int i=0; i<n; i++){ sort(vd[i].begin(), vd[i].end()); for(auto x:vd[i]) mx[i]=max(mx[i], x.second+1); } vector<RangeAddPointGet<ll>> seg(n), segc(id); for(int i=0; i<n; i++){ seg[i].init(mx[i]); } for(int i=0; i<id; i++){ sort(vdc[i].begin(), vdc[i].end()); for(auto x:vdc[i]) mxc[i]=max(mxc[i], x.second+1); segc[i].init(mxc[i]); } LCA lca(tree); lca.build(); while(q--){ int x, y; ll z; scanf("%d %d %lld", &x, &y, &z); x--; int x1=x; ll ans=0; while(x1!=-1){ int t=lower_bound(vd[x1].begin(), vd[x1].end(), P(x, 0))-vd[x1].begin(); int d1=vd[x1][t].second; ans+=seg[x1].get(d1); d1=y-lca.dist(x, x1); if(d1<0) d1=-1; seg[x1].add(0, min(d1+1, mx[x1]), z); int p=pc[x1]; x1=par[x1]; if(x1!=-1){ p=ind[{x1, p}]; t=lower_bound(vdc[p].begin(), vdc[p].end(), P(x, 0))-vdc[p].begin(); d1=vdc[p][t].second; ans+=segc[p].get(d1); d1=y-lca.dist(x, x1)-1; if(d1<0) d1=-1; segc[p].add(0, min(d1+1, mxc[p]), -z); } } printf("%lld\n", ans); } return 0; }