제출 #1181888

#제출 시각아이디문제언어결과실행 시간메모리
1181888WH8Inside information (BOI21_servers)C++20
5 / 100
290 ms77440 KiB

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
using namespace std;
using namespace __gnu_pbds;
#define g0(x) get<0>(x)
#define g1(x) get<1>(x)
#define g2(x) get<2>(x)
#define mt make_tuple
#define pb push_back
#define int long long 
#define f first
#define s second
#define pll pair<long long, long long>
const int maxn=120005;
int par[maxn],sub[maxn],m[maxn],twok[maxn][21],depth[maxn];
vector<int> lvl(maxn,-1);
int n,k;
vector<vector<pair<int,int>>> al(maxn),cnt(maxn);
vector<vector<int>> alcent(maxn);
vector<vector<tuple<int,int,int>>> incf(maxn), decf(maxn);

int kpar(int x, int k){ // this is built on the centroid tree 
	for(int i=0;i<21;i++)if ((1 << i) & k) x = twok[x][i];
	return x;
}
int lca(int a, int b){ // this is built on the centroid tree 
	if (depth[a] < depth[b]) swap(a, b);
	int c;
	a = kpar(a, depth[a] - depth[b]);
	if (a == b) {
		c = a;
	}
	else {
		for (int i = 20; i >= 0; i--){
			if (twok[a][i] != twok[b][i]){
				a = twok[a][i], b=twok[b][i];
			}
		}
		c = twok[a][0];
	}
	return c;
}
int dfs_size(int u, int p, int l) { // to find subtree size in original graph
	sub[u] = 1; // Subtree size is 1
	for (auto [v,w] : al[u]) {
		if (lvl[v] != -1){
			//printf("already added, skipping\n");
			continue; // Already added to centroid tree
		}
		if (v == p) continue;
		sub[u] += dfs_size(v, u, l); // Increase size of subtree
	}
	return sub[u];
}
int get_centroid(int u, int p, int n) { // to find centroid (after dfs_size)
	for (auto [v,w] : al[u]) {
		if (lvl[v] != -1) continue; // Already added to centroid tree
		if (v != p && sub[v] > n / 2) {
			return get_centroid(v, u, n); // DFS to that node
		}
	}
	return u; // No child has size more than n/2, hence you are the centroid
}

// Building from node u, with a parent p and level l
int build(int u, int p, int l) {
	int n = dfs_size(u, p, l); // Find the size of each subtree
	int cent = get_centroid(u, p, n); // Find the centroid
	if (p == -1) p = -1; // Parent of root is -1 / can also set to yourself = cent
	//debug(cent); debug(p);
	par[cent] = p; // Set the parent of centroid to the previous centroid
	if(p!=-1){
		alcent[cent].pb(p);
		alcent[p].pb(cent);
	}
	lvl[cent] = l;
	for (auto [v,w] : al[cent]) {
		if (lvl[v] != -1) continue;
		// If we have already added to centroid then we ignore
		build(v, cent, l + 1); // Recursively build each subtree
	}
	return cent;
}

//To construct the centroid tree, call build(root, -1, 0);

void dfs_depth(int x, int p){
	for (auto [it,w] : al[x]){
		if (it == p) continue;
		depth[it] = depth[x] + 1;
		twok[it][0] = x;
		dfs_depth(it, x);
	}
}

void dfs_incf(int x, int p, int prv, int st, int ori){
	for(auto [u,t]:al[x]){
		if(lvl[u]<=lvl[ori] or u==p)continue; // we only look at nodes in the centroid subtree of ori
		if(t <= prv) continue; // inc 
		int go=st;
		if(st==-1)go=t;
		incf[ori].push_back({u,go,t});
		dfs_incf(u, x, t, go, ori);
	}
}

void dfs_decf(int x, int p, int prv, int st, int ori){
	for(auto [u,t]:al[x]){
		if(lvl[u]<=lvl[ori] or u==p)continue; // we only look at nodes in the centroid subtree of ori
		if(t >= prv) continue; // dec.
		int go=st;
		if(st==-1)go=t; 
		decf[ori].push_back({u,go,t});
		dfs_decf(u, x, t,go, ori);
	}
}

void dfs_cnt(int x, int p){
	for(auto u:alcent[x]){
		if(u==p)continue; // we only look at nodes in the centroid subtree of ori
		dfs_cnt(u,x);
		for(auto it:cnt[u]){
			cnt[x].pb(it);
		}
	}
}

signed main(){
	vector<tuple<int,int,int>> query;
	cin>>n>>k;
	vector<int> type(n+k-1,-1), ans(n+k-1,0);
	for(int i=0;i<n+k-1;i++){
		char ins;int a,b;cin>>ins>>a;
		if(ins=='S'){
			cin>>b;
			type[i]=0;
			al[a].pb({b,i});
			al[b].pb({a,i});
		}
		else if(ins=='Q'){
			type[i]=1;
			cin>>b;
			query.pb({a,b,i});
		}
		else {
			type[i]=2;
			cnt[a].pb({a,i});
		}
	}
	int cent=build(1,-1,0); // this is the root of the centroid tree.
	dfs_depth(cent,-1);
	for (int i=1;i<21;i++){
		for(int j=1;j<=n;j++){
			twok[j][i] = twok[twok[j][i-1]][i-1];
		}
	}
	
	//~ for(int i=1;i<=n;i++){
		//~ cout<<"node "<<i<<endl;
		//~ for(auto it:alcent[i])cout<<it<<", ";
		//~ cout<<endl;
		//~ printf("node %lld has level %lld in centroid has parent %lld\n",i,lvl[i],par[i]);
	//~ }
	//~ return 0;
	for(int i=1;i<=n;i++){
		dfs_incf(i,-1,-1,-1, i);
		dfs_decf(i,-1,1e15,-1,i);
		incf[i].pb({i,1e15,-1});
		decf[i].pb({i,-1,-2});
	}
	dfs_cnt(cent,-1);
	//~ for(int i=1;i<=n;i++){
		//~ printf("node %lld ------------------------\n",i);
		//~ cout<<"incf: ";
		//~ for(auto [u,st,t]:incf[i]){
			//~ printf("u %lld, st %lld, t %lld\n",u,st,t);
		//~ }
		//~ cout<<"\n";
		//~ cout<<"decf: ";
		//~ for(auto [u,st,t]:decf[i]){
			//~ printf("u %lld, st %lld, t %lld\n",u,st,t);
		//~ }
		//~ cout<<"\n";
		//~ cout<<"cnt: ";
		//~ for(auto [a,b]:cnt[i]){
			//~ printf("from a %lld at time %lld\n",a,b);
		//~ }
		//~ cout<<"---------------------\n";
	//~ }
	for(int i=1;i<=n;i++){
		sort(decf[i].begin(),decf[i].end());
		sort(incf[i].begin(),incf[i].end(),[&](auto a, auto b){
			return get<1>(a)<get<1>(b);
		});
		vector<tuple<int,int,int>> abs;
		int ptr=incf[i].size()-1;
		for(auto [from, time] : cnt[i]){
			//~ printf("i=%lld, checking validity of from %lld, time %lld\n",i,from,time);
			auto it=lower_bound(decf[i].begin(),decf[i].end(),mt(from,LLONG_MIN,LLONG_MIN));
			//~ if(it!=decf[i].end()){
				//~ printf("from is actually %lld\n", get<0>(*it));
			//~ }
			if(it==decf[i].end() 
			or get<0>(*it)!=from // path is not increasing to parent even.
			or get<1>(*it)>time// path cannot even be taken.
			)continue; 
			abs.push_back({get<1>(*it),get<2>(*it),time});
			//~ printf("added\n");
		}
		sort(abs.begin(),abs.end(),greater<tuple<int,int,int>>());
		ordered_set oset;
		for(auto [a,b, time] : abs){
			
			while(ptr>=0 and get<1>(incf[i][ptr])>a){
				oset.insert(get<2>(incf[i][ptr]));
				ptr--;
			}
			int cont=oset.order_of_key(time);
			ans[time]+=cont;
			//~ printf("anc %lld, a %lld, b %lld, time %lld, cont %lld\n",i,a,b,time,cont);
		}
	}
	for(int i=1;i<=n;i++){
		sort(incf[i].begin(),incf[i].end());
	}
	for(auto [a,b,time]:query){
		// b is in dec from anc, a is in inc from anc
		if(a==b){
			ans[time]=1;
		}
		else{
			int anc=lca(a,b);
			auto it1=lower_bound(decf[anc].begin(),decf[anc].end(),mt(b,LLONG_MIN,LLONG_MIN));
			auto it2=lower_bound(incf[anc].begin(),incf[anc].end(),mt(a,LLONG_MIN,LLONG_MIN));
			if(it1==decf[anc].end() or it2==incf[anc].end() 
			or get<0>(*it1)!=b or get<0>(*it2)!=a 
			or get<1>(*it2)<get<1>(*it1) or get<2>(*it2)>time
			or get<1>(*it1)>time
			){
				ans[time]=0;
			}
			else {
				ans[time]=1;
				//~ printf("a %lld, b %lld, time %lld, endtime %lld\n",a,b,time,get<2>(*it2));
			}
		}
	}
	for(int i=0;i<n+k-1;i++){
		if(type[i]==0)continue;
		else if(type[i]==1){
			if(ans[i])cout<<"yes\n";
			else cout<<"no\n";
		}
		else{
			cout<<ans[i]<<"\n";
		}
	}
	
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...