結果

問題 No.399 動的な領主
ユーザー kenta255kenta255
提出日時 2021-08-27 23:18:25
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 661 ms / 2,000 ms
コード長 6,603 bytes
コンパイル時間 2,616 ms
コンパイル使用メモリ 226,944 KB
実行使用メモリ 14,944 KB
最終ジャッジ日時 2024-05-01 04:13:46
合計ジャッジ時間 9,757 ms
ジャッジサーバーID
(参考情報)
judge5 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,812 KB
testcase_01 AC 1 ms
6,812 KB
testcase_02 AC 2 ms
6,944 KB
testcase_03 AC 1 ms
6,940 KB
testcase_04 AC 4 ms
6,944 KB
testcase_05 AC 42 ms
6,940 KB
testcase_06 AC 627 ms
14,248 KB
testcase_07 AC 595 ms
14,256 KB
testcase_08 AC 588 ms
13,052 KB
testcase_09 AC 617 ms
14,576 KB
testcase_10 AC 6 ms
6,944 KB
testcase_11 AC 31 ms
6,944 KB
testcase_12 AC 426 ms
14,944 KB
testcase_13 AC 425 ms
14,880 KB
testcase_14 AC 146 ms
13,220 KB
testcase_15 AC 213 ms
13,092 KB
testcase_16 AC 306 ms
14,580 KB
testcase_17 AC 661 ms
14,452 KB
testcase_18 AC 596 ms
14,316 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define P pair<ll,ll>
#define FOR(I,A,B) for(ll I = ll(A); I < ll(B); ++I)
#define FORR(I,A,B) for(ll I = ll((B)-1); I >= ll(A); --I)
#define TO(x,t,f) ((x)?(t):(f))
#define SORT(x) (sort(x.begin(),x.end())) // 0 2 2 3 4 5 8 9
#define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin()) //xi>=v  x is sorted
#define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin()) //xi>v  x is sorted
#define NUM(x,v) (POSU(x,v)-POSL(x,v))  //x is sorted
#define REV(x) (reverse(x.begin(),x.end())) //reverse
ll gcd_(ll a,ll b){if(a%b==0)return b;return gcd_(b,a%b);}
ll lcm_(ll a,ll b){ll c=gcd_(a,b);return ((a/c)*b);}
#define NEXTP(x) next_permutation(x.begin(),x.end())
const ll INF=ll(1e16)+ll(7);
const ll MOD=1000000007LL;
#define out(a) cout<<fixed<<setprecision((a))
//tie(a,b,c) = make_tuple(10,9,87);
#define pop_(a) __builtin_popcount((a))
ll keta(ll a){ll r=0;while(a){a/=10;r++;}return r;}
ll ketawa(ll a){ll r=0;while(a){r+=a%10;a/=10;}return r;}
#define num_l(a,v) POSL(a,v) //v未満の要素数
#define num_eql(a,v) POSU(a,v) //v以下の要素数
#define num_h(a,v) (a.size() - POSU(a,v)) //vより大きい要素数
#define num_eqh(a,v) (a.size() - POSL(a,v)) //v以上の要素数




struct HL{ // 0indexed

	vector<int> HLvector; // 頂点の列
	vector<int> root_union; // root_union[i] = HLした後 頂点 HLvector[i] の根の頂点番号
	vector<int> par; // par[i]=頂点iの親 HL分解する前のグラフで1つ根に向かったやつ
	vector<int> index; // index[i]=j <=> HLvector[j]=i
	vector<int> depth; //depth[i]=頂点iの元の木での深さ
	void make_HLvector(const vector<int> &u,const vector<int> &v){
		HLvector.clear();
		root_union.clear();
		int N = u.size() + 1;
		par.resize(N);
		for(int i=0;i<N;i++) par[i] = -1;
		auto ltof = leaf_to_root(u,v,0);
		vector<int> num(N,1);
		vector<vector<int>> G(N);
		for(auto e:ltof) num[e.first] += num[e.second];
		for(auto e:ltof) par[e.second] = e.first;
		for(int i=0;i<N-1;i++){
			G[u[i]].push_back(v[i]);
			G[v[i]].push_back(u[i]);
		}
		stack< pair<int,int> > st;
		st.push({0,0}); // 頂点,最も浅い頂点
		while(st.size()){
			int i = st.top().first;
			int p = st.top().second;
			st.pop();
			HLvector.push_back(i);
			root_union.push_back(p);
			int val = 0 , big_child = 0;
			for(auto v:G[i]){
				if(num[v] > num[i]) continue; // 親には戻らない
				if(num[v] > val){
					val = num[v];
					big_child = v;
				}
			}
			if(val == 0) continue;
			for(auto v:G[i]){
				if(num[v] > num[i] || v == big_child) continue;
				st.push({v,v});
			}
			st.push({big_child,p});
		}
		index.resize(N);
		for(int i=0;i<N;i++){
			index[ HLvector[i] ] = i;
		}
		reverse(ltof.begin(), ltof.end());
		depth.resize(N);
		depth[0] = 0;
		for(auto e:ltof) depth[e.second] = depth[e.first] + 1; 
	}

	vector< pair<int,int> > index_route(int u,int v){
		// u,vパスを連結成分で区切った時のパスの(HLvectorの)indexを示す
		vector< pair<int,int> > res;
		while(root_union[index[u]] != root_union[index[v]]){
			if(depth[ root_union[index[u]] ] < depth[ root_union[index[v]] ]) swap(u,v);
			int a = root_union[ index[u] ];
			//u と a のindex
			res.push_back({  index[a]  , index[u]  });
			u = par[a];
			assert(u>=0);
		}
		res.push_back({min(index[u],index[v]),max(index[u],index[v])});
		return res;
	}

	vector< pair<int,int> > leaf_to_root(const vector<int> &u,const vector<int> &v,const int root){
		// return <parent,child>
		int yet = -1;
		vector<int> d(u.size()+1,yet);
		vector< pair<int,int> > res;
		queue<int> Q;
		Q.push(root);
		d[root] = 0;
		vector< vector<int> > G(u.size()+1);
		for(int i=0;i<u.size();i++){
			G[u[i]].push_back(v[i]);
			G[v[i]].push_back(u[i]);
		}
		while( Q.size() ){
			int now = Q.front();
			Q.pop();
			for(auto nex:G[now]){
				if(d[nex]!=yet)continue;
				d[nex] = d[now] + 1;
				Q.push(nex);
				res.push_back( make_pair(now,nex) );
			}
		}
		reverse(res.begin(), res.end());
		return res;// return <parent,child>
	}


};

template <typename T>
class Lazy_Seg_Tree{
public: // 0-index
	// buketは区間変更の値  datは区間の答え
	// initial_d,initial_b は buket dat の 単位元
	T make_dat_from_buket(T da, T bu, T s){//dat[k] = make_dat_from_buket(dat[k],buket[k],r-l);
		return da + bu * s;
	}
	T buket_to_child(T ch, T pa){// buket[2*k+1] = buket_to_child(buket[2*k+1],buket[k]);
		return ch + pa;
	}
	T buket_update(T bu , T x , T s){// buket[k] = buket_update(buket[k],x,r-l);
		return bu + x;
	}
	T dat_update(T dc1, T dc2){// dat[k] = dat_update(dat[2*k+1],dat[2*k+2]);
		return (dc1 + dc2);
	}

	vector<T> dat,buket;
	T initial_d,initial_b,M;
	int n;
	Lazy_Seg_Tree(int n0_=1,T initial_dat=1,T initial_buket=0 ,T M_=1){
		initsize(n0_,initial_dat,initial_buket,M_);
	}
	void initsize(int n0,T initial_da,T initial_bu,T M_){
		M = M_;
		initial_d = initial_da;
		initial_b = initial_bu;
		int k=1;
		while(k<n0)k*=2;
		n = k;
		dat.resize(2*n-1);
		buket.resize(2*n-1);
		for(int i=0;i<2*n-1;i++)dat[i]=initial_da;
		for(int i=0;i<2*n-1;i++)buket[i]=initial_bu;
	}
	
	void eval(int k,int l,int r){
		if(buket[k] != initial_b){
			dat[k] = make_dat_from_buket(dat[k],buket[k],r-l);
			if(r-l>1){
				buket[2*k+1] = buket_to_child(buket[2*k+1],buket[k]);
				buket[2*k+2] = buket_to_child(buket[2*k+2],buket[k]);
			}
			buket[k] = initial_b;
		}
	}

	void operate(int a,int b, T x, int k=0,int l=0, int r=-1){
		if(r<0)r=n;
		eval(k,l,r);
		if(b<=l || r<=a)return;
		if(a<=l && r<=b){
			buket[k] = buket_update(buket[k],x,r-l);
			eval(k,l,r);
		}else{
			operate(a,b,x,2*k+1,l,(l+r)/2);
			operate(a,b,x,2*k+2,(l+r)/2,r);
			dat[k] = dat_update(dat[2*k+1],dat[2*k+2]);
		}
	}
	T get(int a,int b,int k=0,int l=0,int r=-1){
		if(r<0)r=n;
		if(b<=l || r<=a) return initial_d;
		eval(k,l,r);
		if(a<=l && r<=b) return dat[k];
		T vl = get(a,b,2*k+1,l,(l+r)/2);
		T vr = get(a,b,2*k+2,(l+r)/2,r);
		return dat_update(vl,vr);
	}
};



int main(){

	int N;
	cin >> N;
	vector<int> u(N-1),v(N-1);
	FOR(i,0,N-1){
		cin >> u[i] >> v[i];
		u[i]--;
		v[i]--;
	}
	HL hl;
	hl.make_HLvector(u,v);

	Lazy_Seg_Tree<ll> sg(N,0,0,MOD);
	int Q;
	cin >> Q;
	ll ans = 0;
	while(Q--){
		int a,b;
		cin >> a >> b;
		a--;
		b--;
		auto r = hl.index_route(a,b);
		for(auto e:r){
			a = e.first;
			b = e.second;
			sg.operate(a,b+1,1,0,0,-1);
		}
		for(auto e:r){
			ans += sg.get(e.first,e.second+1,0,0,-1);
			/*for(int i=e.first;i<=e.second;i++){
				ans += sg.get(i,i+1,0,0,-1);
			}*/
			//cout << "["<<e.first<<","<<e.second<<"]"<<endl;
		}
	}
	cout << ans << endl;
}
0