经常碰到一类题目,让你在一个具有某种特殊性质(边权>=/<=x)的连通块内做一些操作,有多个询问。
这时候就希望可以找出一种数据结构,使得每个连通块都可以恰好变成一棵子树,然后维护维护就可以了。
能不能找到呢?当然是可以的。
这就是kruskal重构树。在做kruskal的过程中,将加入的边建成一个点,作为它连接的两个集合的父亲。
这样造出的树通常是个大根堆/小根堆,且它和最小生成树的关系非常密切。
noi2018归程
突然发现如果会kruskal重构树的话此题就是Noi2018最简单的一题了。。屠龙勇士至少细节还是比较坑的。。
此题就是找出走>p的边能够到达的所有点,对它们的dis[1]取个min。就是kruskal生成树的裸题。
#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
int x=0; int w=0; char ch=0;
while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return w? -x:x;
}
#define mp make_pair
#define fr first
#define se second
#define pr pair<LL,int>
const LL inf=4e9;
const int N=400005;
const int M=400005;
int nedge,n,m,Nedge,head[N],hed[N],vis[N],root,cnt,f[N],F[N][25];
LL dis[N],w[N],val[N];
struct node{ int a,b,len,het; }e[M];
bool operator < (node x,node y){ return (x.het>y.het); }
struct Edge{ int to,nex,cst; }edge[M<<1],E[M<<1];
priority_queue< pr ,vector< pr >,greater< pr> > q;
void addedge(int a,int b,int c){
edge[nedge].to=b; edge[nedge].nex=hed[a]; edge[nedge].cst=c; hed[a]=nedge++;
}
void dijkstra(int s){
rep(i,1,n) dis[i]=inf; dis[s]=0; ms(vis,0,vis); while (!q.empty()) q.pop(); q.push(mp(dis[s],s));
while (!q.empty()){
pr x=q.top(); q.pop(); int k=x.se; if (vis[k]) continue; vis[k]=1;
repedge(i,k){ int v=edge[i].to; LL tmp=dis[k]+edge[i].cst;
if (tmp<dis[v]){ dis[v]=tmp; q.push(mp(dis[v],v)); }
}
}
}
#define repE(x,y) for(int x=head[y]; ~x; x=E[x].nex)
void addE(int a,int b){
E[Nedge].to=b; E[Nedge].nex=head[a]; head[a]=Nedge++;
}
int gf(int k){ return (k==f[k])? k:f[k]=gf(f[k]); }
void build_kruskal(){
sort(e+1,e+m+1); rep(i,1,2*n) f[i]=i; cnt=n;
Nedge=0; ms(head,-1,head);
rep(i,1,m){
int fa=gf(e[i].a); int fb=gf(e[i].b);
if (fa==fb) continue;
f[fa]=f[fb]=++cnt; w[cnt]=e[i].het;
addE(cnt,fa); addE(cnt,fb);
}
root=cnt;
}
void dfs(int k){
val[k]=(k<=n)? dis[k]:inf;
repE(i,k){
int v=E[i].to; F[v][0]=k; dfs(v);
val[k]=min(val[k],val[v]);
}
}
LL solve(int v,int p){
downrep(i,20,0) if (w[F[v][i]]>p) v=F[v][i];
return val[v];
}
int main(){
int cas=read();
rep(cl,1,cas){
n=read(); m=read(); nedge=0; ms(hed,-1,hed);
rep(i,1,m) e[i].a=read(),e[i].b=read(),e[i].len=read(),e[i].het=read();
rep(i,1,m) addedge(e[i].a,e[i].b,e[i].len),addedge(e[i].b,e[i].a,e[i].len);
dijkstra(1); build_kruskal();
F[root][0]=root; dfs(root); rep(j,1,20) rep(i,1,cnt) F[i][j]=F[F[i][j-1]][j-1];
int q=read(); int K=read(); int S=read(); LL ans=0;
rep(i,1,q){
int v=read(); LL p=read();
v=(v+K*ans-1)%n+1; p=(p+K*ans)%(S+1);
ans=solve(v,p); printf("%lld\n",ans);
}
}
return 0;
}
UPD:bzoj3551 peaks强制在线。(3545非强制在线,可以用排序+启发式合并)
套个主席树就好了。
#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
int x=0; int w=0; char ch=0;
while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return w? -x:x;
}
const int N=200005;
const int M=500005;
int root,val[N],n,m,q,hed[N],nedge,f[N],cnt,pres[N],h[N],w[N],F[N][25],tin[N],tout[N],rot[N],tot,dt;
map<int,int> mat,rk;
struct Edge{ int to,nex; }edge[M<<1];
struct node{ int a,b,c; }e[M];
bool operator < (node x,node y){ return (x.c<y.c); }
struct Segment{ int sum,lson,rson; }tr[N*20];
void addedge(int a,int b){
edge[nedge].to=b; edge[nedge].nex=hed[a]; hed[a]=nedge++;
}
int gf(int k){ return (k==f[k])? k:f[k]=gf(f[k]); }
void build_kruskal(){
nedge=0; ms(hed,-1,hed);
sort(e+1,e+m+1); rep(i,1,2*n) f[i]=i; cnt=n;
rep(i,1,m){
int fa=gf(e[i].a); int fb=gf(e[i].b);
if (fa==fb) continue;
f[fa]=f[fb]=++cnt; w[cnt]=e[i].c;
addedge(cnt,fa); addedge(cnt,fb);
}
root=cnt;
}
void dfs(int k){
if (k<=n){ tin[k]=tout[k]=++tot; val[tot]=h[k]; }
repedge(i,k){
int v=edge[i].to;
F[v][0]=k; dfs(v); tin[k]=(!tin[k])? tin[v]:min(tin[v],tin[k]);
tout[k]=max(tout[k],tout[v]);
}
}
#define mid ((l+r)>>1)
#define lc (tr[nod].lson)
#define rc (tr[nod].rson)
#define flc (tr[fnod].lson)
#define frc (tr[fnod].rson)
#define fr first
#define se second
void pushup(int nod){ tr[nod].sum=tr[lc].sum+tr[rc].sum; }
void build(int l,int r,int &nod){
nod=++dt; if (l==r){ tr[nod].sum=0; return; }
build(l,mid,lc); build(mid+1,r,rc); pushup(nod);
}
void upd(int l,int r,int fnod,int &nod,int x){
nod=++dt; tr[nod]=tr[fnod]; if (l==r){ tr[nod].sum++; return; }
if (x<=mid) upd(l,mid,flc,lc,x); else upd(mid+1,r,frc,rc,x);
pushup(nod);
}
void build_segment(){
rep(i,1,n) mat[val[i]]++; int tmp=0;
for(map<int,int> :: iterator i=mat.begin(); i!=mat.end(); i++)
{ rk[(i->fr)]=++tmp; pres[tmp]=(i->fr); }
dt=rot[0]=0; build(1,n,rot[0]);
rep(i,1,n) upd(1,n,rot[i-1],rot[i],rk[val[i]]);
}
int query(int l,int r,int fnod,int nod,int x){
if (l==r) return (tr[nod].sum-tr[fnod].sum>=x)? pres[l]:(-1);
return (x<=tr[lc].sum-tr[flc].sum)? query(l,mid,flc,lc,x):
query(mid+1,r,frc,rc,x-(tr[lc].sum-tr[flc].sum));
}
int que(int l,int r,int k){
int sum=tr[rot[r]].sum-tr[rot[l-1]].sum;
return (k>sum)? (-1):query(1,n,rot[l-1],rot[r],sum-k+1);
}
int solve(int v,int x,int k){
downrep(i,20,0) if (w[F[v][i]]<=x) v=F[v][i];
return que(tin[v],tout[v],k);
}
int main(){
n=read(); m=read(); q=read(); rep(i,1,n) h[i]=read();
rep(i,1,m) e[i].a=read(),e[i].b=read(),e[i].c=read();
build_kruskal(); F[root][0]=root; dfs(root);
rep(j,1,20) rep(i,1,cnt) F[i][j]=F[F[i][j-1]][j-1]; build_segment(); int ans=0;
rep(i,1,q){
int v=read(); int x=read(); int k=read();
if (ans!=-1){ v^=ans; x^=ans; k^=ans; }
ans=solve(v,x,k); printf("%d\n",ans);
}
return 0;
}