Codeforces 588E 树上主席树+Lca
Codeforces 588E Duff in the Army
西安邀请赛网络赛J的升级版本,要求输出具体的方案,这题就没办法离线水过去了。对dfs序建一个主席树,那么对于每个询问答案就是
$sum[u]+sum[v]-sum[lca(u,v)]-sum[fa[lca(u,v)]]$
之后就不难了,实现起来比较复杂,不过写的蛮快的,wa了之后扫了一下主席树感觉没什么问题,就扫了一眼lca 发现最后求lca的部分写错了。
#include
using namespace std;
#define dd(x) cout<<#x<<"="< vi;
typedef pair pi;
int dep[maxn], f[maxn][32],cnt, T[maxn];
int n, m, q;
vector num[maxn], v[maxn];
vector ans;
struct node{
int sum,l,r;
node() {sum=l=r=0;}
}t[maxn<<6];
void update(int pre,int &now,int l,int r,int pos){
now = ++cnt;
t[now].sum = t[pre].sum+1;
if(l==r) return ;
t[now]. l = t[pre].l;
t[now].r = t[pre].r;
int mid = l+r >> 1;
if(mid>=pos) update(t[pre].l,t[now].l,l,mid,pos);
else update(t[pre].r,t[now].r,mid+1,r,pos);
}
void dfs(int x,int p,int d){
dep[x] = d;
f[x][0] = p;
rep(i,1,30)
f[x][i] = f[f[x][i-1]][i-1];
T[x] = T[p];
for(auto u:num[x])
update(T[x],T[x],1,m,u);
for(auto u:v[x])
if(u!=p)
dfs(u,x,d+1);
}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
for(int i=29,d=dep[u]-dep[v];i>=0;i--)
if(d>>i&1) u=f[u][i];
if(u==v) return v;
for(int i=29;i>=0;i--)
if(f[u][i]!=f[v][i])
u=f[u][i], v=f[v][i];
return f[u][0];
}
void qr(int x,int y,int z,int d,int l,int r,int k){
int sl = t[t[x].l].sum + t[t[y].l].sum -t[t[z].l].sum - t[t[d].l].sum;
if(l==r){
if(k)ans.pb(l);
return ;
}
int mid = l+r >> 1;
if(sl>=k) qr(t[x].l,t[y].l,t[z].l,t[d].l,l,mid,k);
else {
if(sl) qr(t[x].l,t[y].l,t[z].l,t[d].l,l,mid,sl);
qr(t[x].r,t[y].r,t[z].r,t[d].r,mid+1,r,k-sl);
}
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> q;
rep(i,0,n-1){
int x,y;
cin >> x >> y;
v[x].pb(y);
v[y].pb(x);
}
rep(i,0,m){
int x;
cin >> x;
num[x].pb(i+1);
}
dfs(1,1,0);
rep(i,0,q){
int x,y,a;
ans.clear();
cin >> x>>y>> a;
int l=lca(x,y), d=f[l][0];
if(l==1) d=0;
int k = min(a,t[T[x]].sum+t[T[y]].sum-t[T[l]].sum-t[T[d]].sum);
qr(T[x],T[y],T[l],T[d],1,m,k);
cout << sz(ans);
for(auto i:ans )cout << " " <