Duff in the Army codeforces 588E 树上主席树+lca
Recently Duff has been a soldier in the army. Malek is her commander.
Their country, Andarz Gu has n cities (numbered from 1 to n) and n - 1 bidirectional roads. Each road connects two different cities. There exist a unique path between any two cities.
There are also m people living in Andarz Gu (numbered from 1 to m). Each person has and ID number. ID number of i - th person is i and he/she lives in city number ci. Note that there may be more than one person in a city, also there may be no people living in the city.
Malek loves to order. That’s why he asks Duff to answer to q queries. In each query, he gives her numbers v, u and a.
To answer a query:
Assume there are x people living in the cities lying on the path from city v to city u. Assume these people’s IDs are p1, p2, …, px in increasing order.
If k = min(x, a), then Duff should tell Malek numbers k, p1, p2, …, pk in this order. In the other words, Malek wants to know a minimums on that path (or less, if there are less than a people).
Duff is very busy at the moment, so she asked you to help her and answer the queries.
Input
The first line of input contains three integers, n, m and q (1 ≤ n, m, q ≤ 105).
The next n - 1 lines contain the roads. Each line contains two integers v and u, endpoints of a road (1 ≤ v, u ≤ n, v ≠ u).
Next line contains m integers c1, c2, …, cm separated by spaces (1 ≤ ci ≤ n for each 1 ≤ i ≤ m).
Next q lines contain the queries. Each of them contains three integers, v, u and a (1 ≤ v, u ≤ n and 1 ≤ a ≤ 10).
Output
For each query, print numbers k, p1, p2, …, pk separated by spaces in one line.
Example
Input
5 4 5
1 3
1 2
1 4
4 5
2 1 4 3
4 5 6
1 5 2
5 5 10
2 3 3
5 3 1
Output
1 3
2 2 3
0
3 1 2 4
1 2
Note
Graph of Andarz Gu in the sample case is as follows (ID of people in each city are written next to them):
一开始看错题了= =题意是:给一棵树n个点,再给m个人,说明m个人所在的点同时每个人都有一个编号i,
你的任务就是找到 u v这条路的前k个人,输出其编号。
树上主席书+lca
一开始写的版本:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
int n,m,q;
int sum[N*40],ls[N*40],rs[N*40],root[N];
int f[N][20],dep[N];
vector<int> e[N],v,num[N];
int sze;
void update(int pre,int &now,int l,int r,int d,int val)
{
now=++sze;
ls[now]=ls[pre],rs[now]=rs[pre];
sum[now]=sum[pre]+val;
if(l==r) return ;
int mid=(l+r)>>1;
if(d<=mid) update(ls[pre],ls[now],l,mid,d,val);
else update(rs[pre],rs[now],mid+1,r,d,val);
}
void dfs(int x,int y)
{
//build(root[y],root[x],1,m); 本来这样写的,但是这样写会re
root[x]=root[y];//复制上一棵树,不用重新build,获取头节点就好
if(num[x].size())
{
for(int i=0;i<num[x].size();i++)
update(root[x],root[x],1,m,num[x][i],1);
}
dep[x]=dep[y]+1;
for(int i=0;i<e[x].size();i++)
{
if(e[x][i]==y) continue;
int v=e[x][i];
f[v][0]=x;
for(int j=1;f[f[v][j-1]][j-1];j++)
f[v][j]=f[f[v][j-1]][j-1];
dfs(v,x);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int t=dep[x]-dep[y];
for(int i=0;i<=16;i++)
if((1<<i)&t)x=f[x][i];
for(int i=16;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
if(x==y)return x;
return f[x][0];
}
void ask(int aa,int bb,int cc,int dd,int l,int r,int k)
{
// cout<<sum[ls[aa]]<<" "<<sum[ls[bb]]<<" "<<sum[ls[cc]]<<" "<<sum[ls[dd]]<<endl;
int re=sum[ls[aa]]+sum[ls[bb]]-sum[ls[cc]]-sum[ls[dd]];
int hh=sum[rs[aa]]+sum[rs[bb]]-sum[rs[cc]]-sum[rs[dd]];
if(l==r)
{
if(sum[aa]+sum[bb]-sum[cc]-sum[dd])
v.push_back(l);
return ;
}
int mid=(l+r)>>1;
if(re)
ask(ls[aa],ls[bb],ls[cc],ls[dd],l,mid,k);
if(hh&&k-re>0)
ask(rs[aa],rs[bb],rs[cc],rs[dd],mid+1,r,k-re);
}
int main()
{
sze=0;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=m;i++)
{
int d;
scanf("%d",&d);
num[d].push_back(i);
}
dfs(1,0);
for(int i=1;i<=q;i++)
{
int u,vv,k;
scanf("%d%d%d",&u,&vv,&k);
v.clear();
int tt=lca(u,vv);
ask(root[u],root[vv],root[tt],root[f[tt][0]],1,m,k);
printf("%d",v.size() );
for(int j=0;j<v.size();j++)
printf(" %d",v[j] );
printf("\n");
}
}
后来改善了下 发现更方便的写法是每次都找到第k个点就好,反正最多10个
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
int n,m,q;
int sum[N*40],ls[N*40],rs[N*40],root[N];
int f[N][20],dep[N];
vector<int> e[N],v,num[N];
int sze;
void build(int pre,int &now,int l,int r)
{
now=++sze;
ls[now]=ls[pre];
rs[now]=rs[pre];
sum[now]=sum[pre];
if(l==r)
return ;
int mid=(l+r)>>1;
build(ls[pre],ls[now],l,mid);
build(rs[pre],rs[now],mid+1,r);
}
void update(int pre,int &now,int l,int r,int d,int val)
{
now=++sze;
ls[now]=ls[pre],rs[now]=rs[pre];
sum[now]=sum[pre]+val;
if(l==r) return ;
int mid=(l+r)>>1;
if(d<=mid) update(ls[pre],ls[now],l,mid,d,val);
else update(rs[pre],rs[now],mid+1,r,d,val);
}
void dfs(int x,int y)
{
// build(root[y],root[x],1,m);
root[x]=root[y];
if(num[x].size())
{
for(int i=0;i<num[x].size();i++)
update(root[x],root[x],1,m,num[x][i],1);
}
dep[x]=dep[y]+1;
for(int i=0;i<e[x].size();i++)
{
if(e[x][i]==y) continue;
int v=e[x][i];
f[v][0]=x;
for(int j=1;f[f[v][j-1]][j-1];j++)
f[v][j]=f[f[v][j-1]][j-1];
dfs(v,x);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int t=dep[x]-dep[y];
for(int i=0;i<=16;i++)
if((1<<i)&t)x=f[x][i];
for(int i=16;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
if(x==y)return x;
return f[x][0];
}
int ask(int aa,int bb,int cc,int dd,int l,int r,int k)
{
// cout<<sum[ls[aa]]<<" "<<sum[ls[bb]]<<" "<<sum[ls[cc]]<<" "<<sum[ls[dd]]<<endl;
int re=sum[ls[aa]]+sum[ls[bb]]-sum[ls[cc]]-sum[ls[dd]];
if(l==r)
{
// cout<<l<<endl;
if(k==(sum[aa]+sum[bb]-sum[cc]-sum[dd]))
return l;
else return 0;
}
int mid=(l+r)>>1;
if(k<=re)
{
return ask(ls[aa],ls[bb],ls[cc],ls[dd],l,mid,k);
}
else return ask(rs[aa],rs[bb],rs[cc],rs[dd],mid+1,r,k-re);
}
int main()
{
sze=0;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=m;i++)
{
int d;
scanf("%d",&d);
num[d].push_back(i);
}
dfs(1,0);
for(int i=1;i<=q;i++)
{
int u,vv,k;
scanf("%d%d%d",&u,&vv,&k);
v.clear();
int tt=lca(u,vv);
for(int j=1;j<=k;j++)
{
int hh=ask(root[u],root[vv],root[tt],root[f[tt][0]],1,m,j);
if(hh)
v.push_back(hh);
}
printf("%d",v.size() );
for(int j=0;j<v.size();j++)
printf(" %d",v[j] );
printf("\n");
}
}