【HDU5840】This world need more Zhu
题目描述
As we all know, Zhu is the most powerful man. He has the infinite power to protest the world. We need more men like Zhu!
In Duoladuo, this place is like a tree. There are \(n\) vertices and \(n−1\) edges. And the root is 1. Each vertex can reached by any other vertices. Each vertex has a people with value \(A_i\) named Zhu's believer.
Liao is a curious baby, he has \(m\) questions to ask Zhu. But now Zhu is busy, he wants you to help him answer Liao's questions.
Liao's question will be like "u v k".
That means Liao want to know the answer from following code:
ans = 0; cnt = 0;
for x in the shortest path from u to v {
cnt++;
if(cnt mod k == 0) ans = max(ans,a[x]);
}
print(ans).
Please read the hints for more details.
输入
In the first line contains a single positive integer \(T\), indicating number of test case.
In the second line there are two numbers \(n\), \(m. n\) is the size of Duoladuo, \(m\) is the number of Liao's questions.
The next line contains \(n\) integers \(A1,A2,...An\), means the value of ith vertex.
In the next \(n−1\) line contains tow numbers \(u, v\). It means there is an edge between vertex \(u\) and vertex \(v\).
The next \(m\) lines will be the Liao's question:
u v k
\(1≤T≤10,1≤n≤100000,1≤m≤100000,1≤u,v≤n,1≤k, A_i≤1000000000.\)
输出
For each case, output Case #i: (i is the number of the test case, from 1 to \(T\)).
Then, you need to output the answer for every Liao's questions.
Sample Input
1
5 5
1 2 4 1 2
1 2
2 3
3 4
4 5
1 1 1
1 3 2
1 3 100
1 5 2
1 3 1
Sample Output
Case #1:
1
2
0
2
4
Hint
In query 1,there are only one vertex in the path,so the answer is 1.
In query 2,there are three vertices in the path.But only the vertex 2 mod 2 equals to 0.
In query 3,there are three vertices in the path.But no vertices mod 100 equal to 0.
In query 4,there are five vertices in the path.There are two vertices mod 2 equal to 0.So the answer is max(a[2],a[4]) = 2.
In query 5,there are three vertices in the path.And all the vertices mod 1 equal to 0. So the answer is a[3] = 4.
翻译
哎呀,大概看看伪代码就猜得到啦~
给一棵树,每次在u,v路径上编号,u为1号,然后对于编号为k的倍数的,求他们的点权的最大值,没有就输出0。
题解
emmmm本题标准乱搞题 考场上谁会相信这种乱搞。。。
对于询问的\(k\)进行分类。显然当\(k\)比较大的时候,我们暴力往上跳是可以解决的,随机数据远远跑不满。
\(k\)比较小的时候,我们就按照深度\(mod k\)的值建立\(k\)棵线段树,然后在对应的线段树上查找就好了
这里的\(k\)的较小情况取了\(≤20\),发现是可以\(AC\)的。
考场上应该不会有这么奇怪的题=_= 如果人家刚好每个询问都是\(k=21\),然后\(u,v\)是一条长长的链,这个做法肯定T成狗
不过出题人也不一定猜得到你的\(k\)取多少/cy 所以这个就看\(RP\)了
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[200010];
int ans[200010];
struct qwq{
int v;
int nxt;
}edge[200010];
int head[200010];
int cnt;
void add(int u,int v){
edge[++cnt].nxt=head[u];
edge[cnt].v=v;
head[u]=cnt;
}
int fa[200010];
int son[200010];
int siz[200010];
int dep[200010];
void dfs1(int u,int ff){
siz[u]=1;
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(v==ff)continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
int ind;
int tim[200010];
int rea[200010];
int top[200010];
void dfs2(int u,int tp){
top[u]=tp;
tim[u]=++ind;
rea[tim[u]]=u;
if(son[u]){
dfs2(son[u],tp);
}
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(v==son[u]||v==fa[u])continue;
dfs2(v,v);
}
}
int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
return v;
}
namespace small{
struct sque{
int u,v;
int id;
sque(int uu,int vv,int idd){u=uu,v=vv,id=idd;}
};
vector<sque> sq[21];
int rt[20];
struct node{
int ls,rs;
int val;
}t[2000010];
int tot;
void update(int &o,int l,int r,int x){
if(!o)o=++tot;
if(l==r){
t[o].val=a[rea[l]];
return;
}
int mid=(l+r)/2;
if(x<=mid)update(t[o].ls,l,mid,x);
else update(t[o].rs,mid+1,r,x);
t[o].val=max(t[t[o].ls].val,t[t[o].rs].val);
}
int query(int o,int l,int r,int L,int R){
if(!o)return 0;
if(L<=l&&r<=R){
return t[o].val;
}
int ret=0;
int mid=(l+r)/2;
if(L<=mid)ret=max(ret,query(t[o].ls,l,mid,L,R));
if(mid<R)ret=max(ret,query(t[o].rs,mid+1,r,L,R));
return ret;
}
int query(int u,int v,int k){
int LCA=lca(u,v);
int ou=rt[(dep[u]+1)%k],ov=rt[(dep[LCA]+k-(dep[u]-dep[LCA]+1)%k)%k];
int ret=0;
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]]){
ret=max(ret,query(ou,1,n,tim[top[u]],tim[u]));
u=fa[top[u]];
}
else {
ret=max(ret,query(ov,1,n,tim[top[v]],tim[v]));
v=fa[top[v]];
}
}
if(dep[u]>dep[v]){
ret=max(ret,query(ou,1,n,tim[v],tim[u]));
}
else {
ret=max(ret,query(ov,1,n,tim[u],tim[v]));
}
return ret;
}
void gao(int k){
tot=0;memset(t,0,sizeof(t));
memset(rt,0,sizeof(rt));
for(int i=1;i<=n;++i){
update(rt[dep[i]%k],1,n,tim[i]);
}
for(int i=0;i<sq[k].size();++i){
int u=sq[k][i].u,v=sq[k][i].v,id=sq[k][i].id;
ans[id]=query(u,v,k);
}
sq[k].clear();
}
}
namespace big{
struct bque{
int s,k;
int tp;
int id;
bque(int ss,int kk,int tpp,int idd){s=ss,k=kk,tp=tpp,id=idd;}
};
vector<bque> bq[200010];
int top;
int stk[200010];
void dfs(int u,int f){
stk[++top]=u;
for(int i=0;i<bq[u].size();++i){
int s=bq[u][i].s,k=bq[u][i].k,tp=bq[u][i].tp,id=bq[u][i].id;
for(int j=top-s;j>0&&dep[stk[j]]>=dep[tp];j-=k){
ans[id]=max(ans[id],a[stk[j]]);
}
}
bq[u].clear();
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
if(v==f)continue;
dfs(v,u);
}
top--;
}
}
int sb=0;
int main(){
//freopen("in.txt","r",stdin);
//freopen("my.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
printf("Case #%d:\n",++sb);
cnt=-1;
memset(head,-1,sizeof(head));
memset(ans,0,sizeof(ans));
dep[1]=0;
memset(son,0,sizeof(son));
ind=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1,-1);
dfs2(1,1);
for(int i=1;i<=m;++i){
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
if(k<=20){
small::sq[k].push_back(small::sque(u,v,i));
}
else {
int LCA=lca(u,v);
big::bq[u].push_back(big::bque(k-1,k,LCA,i));
big::bq[v].push_back(big::bque((dep[u]+dep[v]-2*dep[LCA]+1)%k,k,LCA,i));
}
}
for(int i=1;i<=20;++i){
if(small::sq[i].size())small::gao(i);
}
big::dfs(1,-1);
for(int i=1;i<=m;++i){
printf("%d\n",ans[i]);
}
}
}