不要…不要误会,我不是针对莫队,我是说在座的莫队都假了。
(虽然我也写的假莫队)
给你一棵树和若干条带权模式链,多次询问,给出一条链,求所有为其子链的模式链中,权值第$k$小是多少。
用树上莫队+分块解决。
关键在于怎么判断某条模式链是否为当前区间代表的链的子链。
首先能想到每个点开一个vector
,把每个模式链插进两端点的vector
中。移动指针时,扫一遍vector
,如果一条链的另一个端点也位于当前链,就把它加进块里/从块里删除。
但这个做法复杂度对吗?
用vector
存信息时,必须保证每个vector
被遍历的次数是均等的,才能把复杂度均摊掉。
显然莫队不能保证每个位置被扫过的次数是均等的。通俗来讲,莫队的指针移动次数是$O(n\sqrt{m})$的,但每个位置被扫过的次数不是$O(\sqrt{m})$的。
这样卡掉这个做法就很容易了,将模式链全部插入第一个块里,询问左端点也全放到第一个块里,构造右端点,使排序后的询问左端点会呈这种方式移动:
复杂度就是$O(nm)$的。只不过数据水没卡。
解决方案:把每个位置按vector
的元素拆成若干个新点,重新制定询问区间。在新序列和新询问区间上跑莫队。
然而这样写很麻烦,细节很繁琐,所以我还是写的假莫队
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define maxn 80005
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int son[maxn],siz[maxn],seg[maxn],deep[maxn],fa[maxn],top[maxn],dis[maxn],ans[maxn],len;
int fir[maxn],en[maxn],be[maxn],pos[maxn],h[maxn],bel[maxn],bc[maxn],c[maxn],num,cnt,all;
vector<pair<int,int> >p[maxn];
vector<pair<int,int> >::iterator iter;
bool vis[maxn];
struct edge{
int pre,to;
}e[maxn];
struct Query{
int l,r,num,lc,k;
bool operator < (const Query &x)const{
if(be[l]!=be[x.l])return be[l]<be[x.l];
if(be[l]&1)return r<x.r;
return r>x.r;
}
}q[maxn>>1];
inline void adde(int from,int to){
e[++num]=(edge){h[from],to};
h[from]=num;
}
void dfs1(int node=1){
pos[fir[node]=++cnt]=node;
siz[node]=1;
for(register int i=h[node],x;i;i=e[i].pre){
x=e[i].to;
if(siz[x])continue;
deep[x]=deep[node]+1,fa[x]=node;
dfs1(x),siz[node]+=siz[x];
if(siz[x]>siz[son[node]])son[node]=x;
}
pos[en[node]=++cnt]=node;
}
void dfs2(int node=1){
seg[node]=++all;
if(!son[node])return;
int x;
top[son[node]]=top[node],dfs2(son[node]);
for(register int i=h[node],x;i;i=e[i].pre){
x=e[i].to;
if(!seg[x])top[x]=x,dfs2(x);
}
}
int lca(int x,int y){
while(top[x]!=top[y])deep[top[x]]<deep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
return deep[x]<deep[y]?x:y;
}
void process(int x,int y,int k,int i){
int l=lca(x,y);
if(l!=x&&l!=y){
if(en[x]>fir[y])swap(x,y);
q[i]=(Query){en[x],fir[y],i,l,k};
}
else {
if(l==y)swap(x,y);
q[i]=(Query){fir[x],fir[y],i,0,k};
}
}
inline void add(int x){++c[x],++bc[bel[x]];}
inline void del(int x){--c[x],--bc[bel[x]];}
inline void modify(int x){
vis[x]^=1;
if(!vis[x]){
for(iter=p[x].begin();iter!=p[x].end();++iter)
if(vis[iter->first])del(iter->second);
}
else {
for(iter=p[x].begin();iter!=p[x].end();++iter)
if(vis[iter->first])add(iter->second);
}
}
int main(){
int n=read(),m=read(),t=read(),sq,L,ssq,x,y,z;
for(register int i=1;i<n;++i)x=read(),y=read(),adde(x,y),adde(y,x);
dfs1(),dfs2();
sq=cnt/sqrt(t),L=cnt/sq+bool(cnt%sq);
for(register int i=1;i<=L;++i)
for(register int j=sq*(i-1)+1,r=min(cnt,j+sq-1);j<=r;++j)
be[j]=i;
while(m--){
x=read(),y=read(),dis[++len]=z=read();
p[x].push_back(make_pair(y,z)),p[y].push_back(make_pair(x,z));
}
sort(dis+1,dis+1+len);
len=unique(dis+1,dis+1+len)-dis-1;
ssq=sqrt(len),L=len/ssq+bool(len%ssq);
for(register int i=1;i<=L;++i)
for(register int j=ssq*(i-1)+1,r=min(len,j+ssq-1);j<=r;++j)
bel[j]=i;
for(register int i=1;i<=n;++i)
for(iter=p[i].begin();iter!=p[i].end();++iter)
iter->second=lower_bound(dis+1,dis+1+len,iter->second)-dis;
for(register int i=1;i<=t;++i){
x=read(),y=read(),z=read();
process(x,y,z,i);
}
sort(q+1,q+1+t);
int l=1,r=1,j;
modify(pos[1]);
for(register int i=1;i<=t;++i){
while(l<q[i].l)modify(pos[l++]);
while(l>q[i].l)modify(pos[--l]);
while(r<q[i].r)modify(pos[++r]);
while(r>q[i].r)modify(pos[r--]);
if(q[i].lc)modify(q[i].lc);
for(j=1;j<=L&&q[i].k>bc[j];++j)q[i].k-=bc[j];
for(j=(j-1)*ssq+1,x=min(n,j+ssq-1);j<=x&&q[i].k>c[j];++j)q[i].k-=c[j];
if(q[i].lc)modify(q[i].lc);
ans[q[i].num]=dis[j];
}
for(register int i=1;i<=t;++i)printf("%d\n",ans[i]);
}