結果

問題 No.1038 TreeAddQuery
ユーザー chocoruskchocorusk
提出日時 2020-04-25 00:02:55
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 3,962 ms / 4,000 ms
コード長 6,815 bytes
コンパイル時間 2,197 ms
コンパイル使用メモリ 164,980 KB
実行使用メモリ 110,952 KB
最終ジャッジ日時 2024-10-15 04:00:02
合計ジャッジ時間 51,119 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 3 ms
6,816 KB
testcase_01 AC 3 ms
6,816 KB
testcase_02 AC 3 ms
6,816 KB
testcase_03 AC 24 ms
7,888 KB
testcase_04 AC 28 ms
7,424 KB
testcase_05 AC 24 ms
8,140 KB
testcase_06 AC 22 ms
7,580 KB
testcase_07 AC 29 ms
7,580 KB
testcase_08 AC 2,406 ms
82,160 KB
testcase_09 AC 2,819 ms
86,900 KB
testcase_10 AC 2,868 ms
87,804 KB
testcase_11 AC 2,894 ms
87,400 KB
testcase_12 AC 2,964 ms
88,764 KB
testcase_13 AC 3,960 ms
110,952 KB
testcase_14 AC 3,617 ms
100,352 KB
testcase_15 AC 3,567 ms
97,928 KB
testcase_16 AC 3,459 ms
96,488 KB
testcase_17 AC 3,339 ms
95,176 KB
testcase_18 AC 670 ms
55,584 KB
testcase_19 AC 769 ms
58,508 KB
testcase_20 AC 749 ms
59,068 KB
testcase_21 AC 895 ms
62,192 KB
testcase_22 AC 1,297 ms
68,996 KB
testcase_23 AC 1,462 ms
71,188 KB
testcase_24 AC 2,306 ms
84,480 KB
testcase_25 AC 3,962 ms
110,648 KB
testcase_26 AC 2,190 ms
83,712 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#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; cin>>a>>b; a--; b--;
		tree[a].push_back(b);
		tree[b].push_back(a);
	}
	myon(0, n);
	for(int i=0; i<n; i++){
		sort(vd[i].begin(), vd[i].end());
	}
	for(int i=0; i<id; i++) sort(vd[i].begin(), vd[i].end());
	vector<RangeAddPointGet<ll>> seg(n), segc(id);
	for(int i=0; i<n; i++){
		seg[i].init(vd[i].size());
	}
	for(int i=0; i<id; i++){
		sort(vdc[i].begin(), vdc[i].end());
		segc[i].init(vdc[i].size());
	}
	LCA lca(tree);
	lca.build();
	while(q--){
		int x, y; ll z;
		cin>>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);
			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);
			}
		}
		printf("%lld\n", ans);
		x1=x;
		while(x1!=-1){
			int d1=y-lca.dist(x, x1);
			if(d1<0) d1=-1;
			if(d1>=(int)vd[x1].size()) d1=(int)vd[x1].size()-1;
			seg[x1].add(0, d1+1, z);
			int p=pc[x1];
			x1=par[x1];
			if(x1!=-1){
				p=ind[{x1, p}];
				d1=y-lca.dist(x, x1)-1;
				if(d1<0) d1=-1;
				if(d1>=(int)vdc[p].size()) d1=(int)vdc[p].size()-1;
				segc[p].add(0, d1+1, -z);
			}
		}
	}
	return 0;
}
0