4009: [HNOI2015]接水果
Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 623 Solved: 293
[ Submit][ Status][ Discuss]
Description
风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。
由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更
加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1
给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条
路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个
盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),
权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第
i 个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水
果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如
图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与
从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择
能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数
的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水
果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
Input
第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。
接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点
按1到 n标号。 接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其
中0≤c≤10^9,a不等于b。
接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,
第k 小一定存在。
Output
对于每个果子,输出一行表示选择的盘子的权值。
Sample Input
10 10 10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
3 2 217394434
10 7 13022269
6 7 283254485
6 8 333042360
4 6 442139372
8 3 225045590
10 4 922205209
10 8 808296330
9 2 486331361
4 9 551176338
1 8 5
3 8 3
3 8 4
1 8 3
4 8 1
2 3 1
2 3 1
2 3 1
2 4 1
1 4 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
3 2 217394434
10 7 13022269
6 7 283254485
6 8 333042360
4 6 442139372
8 3 225045590
10 4 922205209
10 8 808296330
9 2 486331361
4 9 551176338
1 8 5
3 8 3
3 8 4
1 8 3
4 8 1
2 3 1
2 3 1
2 3 1
2 4 1
1 4 1
Sample Output
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
HINT
N,P,Q<=40000。
Source
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 4E4 + 40;
const int T = 18;
const int G = 4;
struct Modify{
int l,r,w,typ; Modify(){}
Modify(int l,int r,int w,int typ): l(l),r(r),w(w),typ(typ){}
};
struct Query{
int pos,k,Num; Query(){}
Query(int pos,int k,int Num): pos(pos),k(k),Num(Num){}
bool operator < (const Query &B) const {return pos < B.pos;}
};
int n,m,q,dfs_clock,cw,W[maxn],w[maxn],A[maxn],B[maxn],dfn[maxn],last[maxn],L[maxn],Ans[maxn],fa[maxn][T],siz[maxn*G],res[maxn];
vector <int> v[maxn],Sum[maxn*G],C[maxn*G];
vector <Modify> M[maxn];
vector <Query> Q[maxn];
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
void Dfs(int x,int from)
{
dfn[x] = ++dfs_clock;
for (int i = 1; i < T; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if (to == from) continue;
L[to] = L[x] + 1; fa[to][0] = x; Dfs(to,x);
}
last[x] = dfs_clock;
}
void Insert(int o,int l,int r,int L,int R,int k)
{
C[o].push_back(L); C[o].push_back(R);
if (l == r) return; int mid = (l + r) >> 1;
if (k <= mid) Insert(o<<1,l,mid,L,R,k);
else Insert(o<<1|1,mid+1,r,L,R,k);
}
void Build_Tree(int o,int l,int r)
{
C[o].push_back(0); C[o].push_back(maxn);
sort(C[o].begin(),C[o].end()); siz[o] = 1;
for (int i = 2; i < C[o].size(); i++)
if (C[o][i] != C[o][i-1]) C[o][++siz[o]] = C[o][i];
for (int i = 0; i <= siz[o]; i++) Sum[o].push_back(0);
while (C[o].size() - 1 > siz[o]) C[o].pop_back();
if (l == r) return; int mid = (l + r) >> 1;
Build_Tree(o<<1,l,mid); Build_Tree(o<<1|1,mid+1,r);
}
void modify(int o,int l,int r,vector <Modify> &g)
{
vector <int> &c = C[o];
for (int i = 0; i < g.size(); i++)
{
int l = lower_bound(c.begin(),c.end(),g[i].l) - c.begin();
int r = lower_bound(c.begin(),c.end(),g[i].r) - c.begin();
int k = g[i].typ;
for (int j = l; j <= siz[o]; j += j&-j) Sum[o][j] += k;
for (int j = r; j <= siz[o]; j += j&-j) Sum[o][j] -= k;
}
if (l == r) return; int mid = (l + r) >> 1;
vector <Modify> g1,g2; g1.clear(); g2.clear();
for (int i = 0; i < g.size(); i++)
if (g[i].w <= mid) g1.push_back(g[i]); else g2.push_back(g[i]);
if (g1.size()) modify(o<<1,l,mid,g1);
if (g2.size()) modify(o<<1|1,mid+1,r,g2);
}
void query(int o,int l,int r,vector <Query> &h)
{
if (l == r)
{
for (int i = 0; i < h.size(); i++)
Ans[h[i].Num] = l;
return;
}
int mid = (l + r) >> 1;
vector <Query> h1,h2; h1.clear(); h2.clear();
vector <int> &sum = Sum[o << 1],&c = C[o << 1];
for (int i = 0; i < h.size(); i++)
{
int pos = lower_bound(c.begin(),c.end(),h[i].pos) - c.begin();
if (c[pos] > h[i].pos) --pos; int tot = 0;
for (int j = pos; j > 0; j -= j&-j) tot += sum[j];
if (tot + res[h[i].Num] >= h[i].k) h1.push_back(h[i]);
else res[h[i].Num] += tot,h2.push_back(h[i]);
}
if (h1.size()) query(o<<1,l,mid,h1);
if (h2.size()) query(o<<1|1,mid+1,r,h2);
}
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
for (int i = T - 1; i >= 0; i--)
if (L[p] - (1 << i) >= L[q]) p = fa[p][i];
if (p == q) return p;
for (int i = T - 1; i >= 0; i--)
if (fa[p][i] != fa[q][i]) p = fa[p][i],q = fa[q][i];
return fa[p][0];
}
int Quickfa(int x,int y)
{
for (int now = 0; y; y >>= 1,now++)
if (y & 1) x = fa[x][now];
return x;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); m = getint(); q = getint();
for (int i = 1; i < n; i++)
{
int x = getint(),y = getint();
v[x].push_back(y);
v[y].push_back(x);
}
L[1] = 1; Dfs(1,0);
for (int i = 1; i <= m; i++)
{
A[i] = getint(); B[i] = getint(); W[i] = w[i] = getint();
if (dfn[A[i]] > dfn[B[i]]) swap(A[i],B[i]);
}
sort(W + 1,W + m + 1); cw = 1;
for (int i = 2; i <= m; i++)
if (W[i] != W[i-1]) W[++cw] = W[i];
for (int i = 1; i <= m; i++)
{
int lca = LCA(A[i],B[i]);
w[i] = lower_bound(W + 1,W + cw + 1,w[i]) - W;
if (lca != A[i])
{
Insert(1,1,cw,dfn[A[i]],last[A[i]] + 1,w[i]);
M[dfn[B[i]]].push_back(Modify(dfn[A[i]],last[A[i]] + 1,w[i],1));
M[last[B[i]] + 1].push_back(Modify(dfn[A[i]],last[A[i]] + 1,w[i],-1));
}
else
{
int z = Quickfa(B[i],L[B[i]] - L[A[i]] - 1);
if (dfn[z] > 1)
{
Insert(1,1,cw,1,dfn[z],w[i]);
M[dfn[B[i]]].push_back(Modify(1,dfn[z],w[i],1));
M[last[B[i]] + 1].push_back(Modify(1,dfn[z],w[i],-1));
}
if (last[z] < n)
{
Insert(1,1,cw,dfn[B[i]],last[B[i]] + 1,w[i]);
M[last[z] + 1].push_back(Modify(dfn[B[i]],last[B[i]] + 1,w[i],1));
M[n + 1].push_back(Modify(dfn[B[i]],last[B[i]] + 1,w[i],-1));
}
}
}
for (int i = 1; i <= q; i++)
{
int x = getint(),y,k;
y = getint(); k = getint();
if (dfn[x] > dfn[y]) swap(x,y);
Q[dfn[y]].push_back(Query(dfn[x],k,i));
}
Build_Tree(1,1,cw);
for (int i = 1; i <= n; i++)
{
if (M[i].size()) modify(1,1,cw,M[i]);
if (Q[i].size()) query(1,1,cw,Q[i]);
}
for (int i = 1; i <= q; i++) printf("%d\n",W[Ans[i]]);
return 0;
}