虽然是NOI-/NOI/CTSC,但感觉还没有平时考试难,可能是这种题太套路了.
给了你一棵树,给了你一些路径,每次询问,u,v两点间的第k小的子路径(必须是给出的那些路径中的)
怎么判某条路径是某条路径的子路径?
一个套路就是用dfs序的区间包含关系.这个套路大概自己推理一下就出来了.
然后发现限制条件是一个二维的,所以这个区间不是一个线段,而是一个矩形,所以用一下扫描线.当然可以用树套树,二维树状数组,但是他们大材小用。注意到不需要修改,而这些数据结构支持修改,所以不需要用。
扫描线就是把一个矩形拆成两条线段,分别是平行于y轴的两条.每个线段记录一下横坐标,记录一下两个纵坐标,然后在记录一下是左边的还是右边的。然后按x排序然后顺次加入,计入左边的就给y1-y2加一,计入右边的就减一.
// luogu-judger-enable-o2
#include
using namespace std;
template <class T>
inline void read(T&data){
register char ch=0;
data=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch<='9'&&ch>='0'){
data=(data<<3)+(data<<1)+(ch^48);
ch=getchar();
}
return;
}
#define rg register
const int _ = 100011;
struct edge {
int nt,to;
}e[_<<1];
int cnt=0,n,head[_],m,q,son[_],size[_],top[_],fa[_],deep[_],Index,dfn[_],low[_];
int Map[_],ans[_];
struct Line{
int ki,x,y1,y2,d,val;
}Q[_<<2],Q1[_<<2],Q2[_<<2];
int tree[_<<2];
inline int lowbit(register int k){return k&(-k);}
inline void modify(register int loc,register int zh){for(register int i=loc;i<=Index+1;i+=lowbit(i))tree[i]+=zh;}
inline int query(register int loc){register int ret=0;for(register int i=loc;i;i-=lowbit(i))ret+=tree[i];return ret;}
void add(register int a,register int b){e[++cnt].to=a,e[cnt].nt=head[b],head[b]=cnt;}
bool cmp(Line a,Line b){return a.valbool cmp2(Line a,Line b){if(a.x!=b.x)return a.xreturn a.kivoid dfsI(register int now,register int ff){
deep[now]=deep[ff]+1,fa[now]=ff,size[now]=1;
for(register int i=head[now];i;i=e[i].nt)if(e[i].to!=ff){
dfsI(e[i].to,now);size[now]+=size[e[i].to];
if(size[e[i].to]>size[son[now]])son[now]=e[i].to;
}
}
void dfsII(register int now,register int topf){
dfn[now]=++Index,top[now]=topf;
if(son[now])dfsII(son[now],topf);
for(register int i=head[now];i;i=e[i].nt)if(dfn[e[i].to]==0)dfsII(e[i].to,e[i].to);
low[now]=++Index;
}
inline int getlca(register int a,register int b,register int &yl){
while(top[a]^top[b]){
if(deep[top[a]]if(deep[a]if(a!=b)
yl=son[b];
return b;
}
inline void Insert(register int a,register int b,register int c,register int d,register int e,register int f){
Q[++cnt].ki=a,Q[cnt].x=b,Q[cnt].y1=c,Q[cnt].y2=e,Q[cnt].val=f,Q[cnt].d=1;
Q[++cnt].ki=a,Q[cnt].x=d+1,Q[cnt].y1=c,Q[cnt].y2=e,Q[cnt].val=f,Q[cnt].d=-1;
}
void divide(register int l,register int r,register int L,register int R){
//cout<
if(l==r){
for(register int i=L;i<=R;++i)
if(Q[i].ki==2)
ans[Q[i].y2]=l;
return;
}
register int mid = (l+r)>>1;
register int t1=0,t2=0;
for(register int i=L;i<=R;++i){
if(Q[i].ki==1){
if(Q[i].val<=mid) Q1[++t1]=Q[i],modify(Q[i].y1,Q[i].d),modify(Q[i].y2+1,-Q[i].d);
else Q2[++t2]=Q[i];
}
else {
register int su=query(Q[i].y1);
if(Q[i].d<=su){Q1[++t1]=Q[i];/*cout<}
else Q[i].d-=su,Q2[++t2]=Q[i]/*,cout<;
}
}
for(register int i=1;i<=t1;++i)Q[i+L-1]=Q1[i];
for(register int i=1;i<=t2;++i)Q[t1+L-1+i]=Q2[i];
divide(l,mid,L,L+t1-1),divide(mid+1,r,L+t1,R);return;
}
int main(){
//freopen("data.in","r",stdin);
//freopen("1.out","w",stdout);
register int a,b,c;
read(n),read(m),read(q);
for(rg int i=1;i1
,0);dfsII(1,1);cnt=0;
for(register int i=1;i<=m;++i){
read(a),read(b),read(c);
if(dfn[a]>dfn[b])swap(a,b);
register int yl=0,lca=getlca(a,b,yl);//cout<
if(lca==a){
if(dfn[yl]>=1)Insert(1,dfn[b],1,low[b],dfn[yl]-1,c);
//if(dfn[yl]
if(yl)Insert(1,low[yl],dfn[b],Index,low[b],c);
}
else Insert(1,dfn[b],dfn[a],low[b],low[a],c);
}
//exit(0);
/*for(register int i=1;i<=cnt;++i){
cout<
a=-1,b=0;
sort(Q+1,Q+cnt+1,cmp);
for(register int i=1;i<=cnt;++i){
if(Q[i].val==a) Q[i].val=b;
else Map[++b]=Q[i].val,a=Q[i].val,Q[i].val=b;
}
//cout<
register int yl=b;
for(register int i=1;i<=q;++i){
read(a),read(b),read(c);
if(dfn[a]>dfn[b])swap(a,b);
Q[++cnt].ki=2,Q[cnt].x=dfn[b],Q[cnt].y1=dfn[a],Q[cnt].y2=i,Q[cnt].d=c;
}
sort(Q+1,Q+cnt+1,cmp2);b=yl;
divide(1,b,1,cnt);
for(register int i=1;i<=q;++i){
cout<