题目描述
给你一颗有
n
个节点的树,给你
题目解析
之前有道题和这个特别相似,把路径
(x,y)
通过端点的
dfn
转化为点对
(dfnx,dfny)
,然后在线段树上进行插入和查询,因为是考试,所以说我一下子就兴奋了,这不就是那道题的翻版吗,把线段树套线段树改成主席树套线段树就行了,于是怒敲代码,然后Wa了。后面才发现自己太单纯了,把盘子转化成点插入,然后查询水果的区间,然而并么有注意到水果中盘子的区间很有可能是不连续的,GG。
好,开始说正解,还是将路径转化为点,然后我们可以发现,如果直接将盘子插入,水果区间查询是查不出来的,盘子包含在水果
(u,v)
内,就是左端点在水果内加上右端点在水果内,然而我们并不能知道水果所代表的区间,也许你会说是
(u−>lca(u,v))+(lca(u,v)−>v)
,但是这两条路径上的
dfn
不一定是连续的。
故,我们将盘子区间插入,水果单点查询,我们可以知道盘子所能接住的水果的区间:
-
u
和
v 是父子关系时(设 depu<depv ),水果左端点就在 u 点子树中,右端点在除v−>u 子树外的其他所有位置。 -
u
和
v 处于 lca(u,v) 的不同子树内,那么左右端点分别在 u 点和v 点的子树中。
(具体的范围就用dfs序实现)
代码
/**************************************************************
Problem: 4009
User: bzjudge2
Language: C++
Result: Accepted
Time:10044 ms
Memory:518264 kb
****************************************************************/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
#define MAXN 40000
#define MAXP 40000
#define MAXQ 40000
#define MAXLOG 16
#define INF 0x3f3f3f3f
typedef long long int LL;
template<class T>
void Read(T &x){
x=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
if(flag)x=-x;
}
int n,p,q,maxlog;
struct leaf{
int tag;
int ls,rs;
}Leaf[MAXN*MAXLOG*MAXLOG*4+100];
int Cntleaf=0;
int newleaf(){
int x=++Cntleaf;
Leaf[x].tag=Leaf[x].ls=Leaf[x].rs=0;
return x;
}
void insert_leaf(int l,int r,int ll,int rr,int last,int &now){
now=newleaf();
Leaf[now]=Leaf[last];
if(l<=ll&&rr<=r){
++Leaf[now].tag;
return;
}
else{
int mid=(ll+rr)>>1;
if(r<=mid)insert_leaf(l,r,ll,mid,Leaf[now].ls,Leaf[now].ls);
else if(mid<l)insert_leaf(l,r,mid+1,rr,Leaf[now].rs,Leaf[now].rs);
else{
insert_leaf(l,mid,ll,mid,Leaf[now].ls,Leaf[now].ls);
insert_leaf(mid+1,r,mid+1,rr,Leaf[now].rs,Leaf[now].rs);
}
}
}
int query_leaf(int pos,int ll,int rr,int now){
if(!now)return 0;
if(ll==rr)return Leaf[now].tag;
int mid=(ll+rr)>>1;
if(pos<=mid)return Leaf[now].tag+query_leaf(pos,ll,mid,Leaf[now].ls);
else return Leaf[now].tag+query_leaf(pos,mid+1,rr,Leaf[now].rs);
}
struct line{
int rtid;
int ls,rs;
}Line[MAXN*MAXLOG*4];
int rt[MAXN+10];
int LineCnt=0;
int newline(){
int x=++LineCnt;
Line[x].rtid=Line[x].ls=Line[x].rs=0;
return x;
}
void insert_line(int l,int r,int ly,int ry,int ll,int rr,int last,int &now){
now=newline();
Line[now]=Line[last];
if(l<=ll&&rr<=r){
insert_leaf(ly,ry,1,n,Line[now].rtid,Line[now].rtid);
return;
}
else{
int mid=(ll+rr)>>1;
if(r<=mid)insert_line(l,r,ly,ry,ll,mid,Line[now].ls,Line[now].ls);
else if(mid<l)insert_line(l,r,ly,ry,mid+1,rr,Line[now].rs,Line[now].rs);
else{
insert_line(l,mid,ly,ry,ll,mid,Line[now].ls,Line[now].ls);
insert_line(mid+1,r,ly,ry,mid+1,rr,Line[now].rs,Line[now].rs);
}
}
}
int query_line(int pos,int y,int ll,int rr,int now){
if(!now)return 0;
int rn=query_leaf(y,1,n,Line[now].rtid);
if(ll==rr)return rn;
int mid=(ll+rr)>>1;
if(pos<=mid)return rn+query_line(pos,y,ll,mid,Line[now].ls);
else return rn+query_line(pos,y,mid+1,rr,Line[now].rs);
}
struct node{
int v;
node *nxt;
}*adj[MAXN+10],Edges[MAXN*2+10],*New=Edges;
void addedges(int u,int v){
node *p=++New;
p->v=v;
p->nxt=adj[u];
adj[u]=p;
p=++New;
p->v=u;
p->nxt=adj[v];
adj[v]=p;
}
int fa[MAXN+10],dep[MAXN+10];
int in[MAXN+10],out[MAXN+10];
int dfn=0;
void dfs(int x,int f){
in[x]=++dfn,fa[x]=f,dep[x]=dep[f]+1;
for(node *p=adj[x];p!=NULL;p=p->nxt)
if(p->v!=f)dfs(p->v,x);
out[x]=dfn;
}
int dp[MAXN+10][MAXLOG+3];
void init(){
maxlog=log(n)/log(2);
for(int i=1;i<=n;++i)dp[i][0]=fa[i];
for(int len=1;len<=maxlog;++len)
for(int i=1;i<=n;++i)dp[i][len]=dp[dp[i][len-1]][len-1];
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
for(int len=maxlog;len>=0;--len)
if(dep[dp[a][len]]>=dep[b])a=dp[a][len];
if(a==b)return a;
for(int len=maxlog;len>=0;--len)
if(dp[a][len]^dp[b][len])a=dp[a][len],b=dp[b][len];
return fa[a];
}
int climb(int a,int d){
int len=0;
while(d){
if(d&1)a=dp[a][len];
d>>=1;
++len;
}
return a;
}
int u[MAXP+10],v[MAXP+10],w[MAXP+10];
int pos[MAXP+10];
bool cmpdish(const int &x,const int &y){
return w[x]<w[y];
}
int main(){
Read(n),Read(p),Read(q);
int a,b,c;
for(int i=1;i<n;++i){
Read(a),Read(b);
addedges(a,b);
}
dfs(1,0);
init();
for(int i=1;i<=p;++i){
Read(u[i]),Read(v[i]),Read(w[i]);
pos[i]=i;
}
sort(pos+1,pos+p+1,cmpdish);
for(int i=1;i<=p;++i){
rt[i]=rt[i-1];
a=u[pos[i]],b=v[pos[i]],c=w[pos[i]];
if(in[a]>in[b])swap(a,b);
int ff=lca(a,b);
if(ff==a){
int tmp=climb(b,dep[b]-dep[ff]-1);
if(in[tmp]>1){
insert_line(1,in[tmp]-1,in[b],out[b],1,n,rt[i],rt[i]);
//printf("Add: (%d,%d)(%d,%d)\n",1,in[tmp]-1,in[b],out[b]);
}
if(out[tmp]<n){
insert_line(in[b],out[b],out[tmp]+1,n,1,n,rt[i],rt[i]);
//printf("Add: (%d,%d)(%d,%d)\n",in[b],out[b],out[tmp]+1,n);
}
}
else{
insert_line(in[a],out[a],in[b],out[b],1,n,rt[i],rt[i]);
//printf("Add: (%d,%d)(%d,%d)\n",in[a],out[a],in[b],out[b]);
}
}
for(int i=1;i<=q;++i){
Read(a),Read(b),Read(c);
if(in[a]>in[b])swap(a,b);
//printf("Query: (%d,%d)\n",in[a],in[b]);
int l=1,r=p,mid;
int ans=0;
while(l<=r){
mid=(l+r)>>1;
if(query_line(in[a],in[b],1,n,rt[mid])>=c){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
printf("%d\n",w[pos[ans]]);
}
}