Kruskal重构树就是一个图利用最小生成树算法建树,但是建树代码如下
int tot=n;
for(i=1;i<=m;i++){
int fx=find(edge[i].x);
int fy=find(edge[i].y);
if(fx!=fy){
pre[fx]=pre[fy]=++tot;
kv[tot].push_back(fx);
kv[tot].push_back(fy);
val[tot]=edge[i].val;
}
if(tot==2*n-1)
break;
}
这样的话重构树其实是有2n-1个节点的,而且这个树的叶子节点都是1到n的原图节点,非叶子节点是标号为[n+1,2n-1]的节点,也就是重构树新建的节点,这些节点的点权值就是之前的边权,而且如果按最小生成树的话,这个树本质是最大堆,最大生成树则相反,为最小堆。
Kruskal重构树适用于求一个无向图,然后给你个点,让你在只能经过边权大于等于x(或者小于x,都差不多,无非是最大生成树还是最小生成树的问题)的边,求能到达的顶点的一些性质(列如个数,权值最大等等,可以通过维护数据结构,虚树等等乱搞)。
方块为扩展的点,即[n+1,2*n-1]这块的点,权值为两个子节点的原图的边权,最终重构树的根节点是2 * n-1.
这样假设我从1出发,只能经过边权小于等于3的边,那么我就在1的父亲节点里找最后一个小于等于3的边即可(因为这是一个大根堆),然后找到了这个父节点假设为fa,那么fa的子树上的叶子节点都是从1满足限制条件能到达的节点,然后就可以通过线段树+dfs序搞最大值啥的。
然后找父节点时要倍增,dp[MAX_N][21],然后
for(i=20;i>=0;i--){
if(val[dp[x][i]]的权值满足限制条件)
x=dp[x][i];
}
//x即为fa节点
牛客 水灾
这个题恶心人,卡常,我过了90%的测试点,把求lca的改成o(n)的应该就能A了,懒得改了。重构树加虚树比如容易理解而且复杂度也是n log的,常数有点大,但是好想点。
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX_N=1001000;
int pre[MAX_N];
struct skt{
int from,to,val;
}edge[MAX_N/2];
//vector<int>v[MAX_N];
int head[MAX_N],ver[MAX_N],Next[MAX_N],tott;
void add(int x,int y){
ver[++tott]=y;Next[tott]=head[x];head[x]=tott;
}
bool cmp(skt a,skt b){
return a.val>b.val;
}
int cnt=0,dfn[MAX_N];
bool cmpp(int x,int y){
return dfn[x]<dfn[y];
}
int aa[MAX_N];
inline int find(int x){
if(x!=pre[x])
pre[x]=find(pre[x]);
return pre[x];
}
int dp[MAX_N][21],dep[MAX_N],n,log_2[MAX_N];
void dfs(int now,int fa){
int i;
dfn[now]=++cnt;
//cout<<now<<"\n";
//for(i=0;i<v[now].size();i++){
for(i=head[now];i;i=Next[i]){
int to=ver[i];
if(to==fa)
continue;
dp[to][0]=now;
dep[to]=dep[now]+1;
dfs(to,now);
}
}
int LCA(int a,int b){
int k=log_2[2*n-1],i;
if(dep[a]<dep[b]){
int c=a;
a=b;
b=c;
}
while(dep[a]!=dep[b]){
for(i=k;i>=0;i--){
if(dep[dp[a][i]]>=dep[b])
a=dp[a][i];
}
}
if(a==b){
return b;
}
for(i=k;i>=0;i--){
if(dp[a][i]!=dp[b][i]){
a=dp[a][i];
b=dp[b][i];
}
}
return dp[a][0];
}
int val[MAX_N];
inline char nc() {
static char buf [100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read() {
static char c=nc(); int x=0,f=1;
for(;c>'9'||c<'0';c=nc()) if(c=='-') f=-1;
for(;c<='9'&&c>='0';c=nc()) x=(x<<3)+(x<<1)+c-48;
return x*f;
}
inline void out(int a){
if(a < 0) {putchar('-'); a = -a;}
if(a >= 10)out(a / 10);
putchar(a % 10 + '0');
}
int main(void){
int m,q,i,j,k;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=m;i++){
edge[i].from=read();
edge[i].to=read();
edge[i].val=read();
}
//scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].val);
sort(edge+1,edge+m+1,cmp);
int tot=n;
for(i=1;i<=2*n;i++){
pre[i]=i;
log_2[i]=log_2[i-1]+(1<<log_2[i-1]==i);
}
for(i=1;i<=n;i++)
val[i]=-1;
for(i=1;i<=m;i++){
int fx=find(edge[i].from);
int fy=find(edge[i].to);
if(fx!=fy){
pre[fx]=pre[fy]=++tot;
val[tot]=edge[i].val;
//cout<<fx<<" "<<tot<<" "<<fy<<"\n";
//v[fx].push_back(tot);
//v[tot].push_back(fx);
//v[fy].push_back(tot);
//v[tot].push_back(fy);
add(tot,fx);
add(tot,fy);
}
if(tot==2*n-1)
break;
}
dfs(2*n-1,0);
dep[0]=-1;
for(i=1;i<=log_2[2*n-1];i++){
for(j=1;j<=2*n-1;j++){
dp[j][i]=dp[dp[j][i-1]][i-1];
}
}
int lastans=0;
for(i=1;i<=q;i++){
//scanf("%d",&k);
k=read();
for(j=1;j<=k;j++){
//scanf("%d",&aa[j]);
aa[j]=read();
aa[j]=aa[j]^lastans;
}
sort(aa+1,aa+k+1,cmpp);
int ans=0;
for(j=2;j<=k;j++){
int lca=LCA(aa[j-1],aa[j]);
ans=max(ans,val[lca]);
}
lastans=ans;
out(lastans);
putchar('\n');
}
return 0;
}
P4768 [NOI2018]归程
求出从1出发的dijkstra,然后每个询问找那个fa节点,然后在他的子树里找dis的最小值即可,前14个测试点很好过,后两个有点恶心人,4s时限,用了快读加o2优化3.99s,不过可以把vector改了,但是太麻烦了。而且多组输入尽量别用memset,然后注意点清空就ok了。
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int MAX_N=201000;
const int INF=0x3f3f3f3f;
vector<int>v[MAX_N],kv[2*MAX_N],w[MAX_N];
int N;
inline int min(int x,int y){
return x<y?x:y;
}
inline int max(int x,int y){
return x<y?x:y;
}
struct skt{
int x,y,dep;
}edge[2*MAX_N];
struct sktt{
int x,d;
friend bool operator<(sktt a,sktt b){
return a.d>b.d;
}
};
int dis[MAX_N];
bool vis[MAX_N];
bool cmp(skt a,skt b){
return a.dep>b.dep;
}
void dijkstra(int x){
for(int i=1;i<=N;i++){
dis[i]=INF;
vis[i]=false;
}
dis[x]=0;
priority_queue<sktt>q;
sktt t;
t.x=x;t.d=0;
q.push(t);
while(!q.empty()){
t=q.top();
q.pop();
x=t.x;
if(vis[x])
continue;
vis[x]=true;
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
int cost=w[x][i];
if(dis[y]>dis[x]+cost){
dis[y]=dis[x]+cost;
t.x=y;
t.d=dis[y];
q.push(t);
}
}
}
}
int pre[2*MAX_N];
int find(int x){
if(x!=pre[x])
pre[x]=find(pre[x]);
return pre[x];
}
int cnt=0,in[2*MAX_N],out[2*MAX_N],pos[2*MAX_N];
int dp[2*MAX_N][21];
void dfs(int x){
int i;
in[x]=++cnt;
pos[cnt]=x;
for(i=0;i<kv[x].size();i++){
int y=kv[x][i];
dp[y][0]=x;
dfs(y);
}
out[x]=cnt;
}
int val[2*MAX_N];
void init(){
int i,j;
for(j=1;j<=20;j++){
for(i=1;i<=2*N-1;i++){
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
}
struct node{
int l,r;
int minl;
}a[MAX_N*8];
void update(int k){
a[k].minl=min(a[k<<1].minl,a[k<<1|1].minl);
}
void build(int k,int l,int r){
a[k].l=l;a[k].r=r;
if(l==r){
if(pos[l]>N)
a[k].minl=INF;
else
a[k].minl=dis[pos[l]];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k);
}
inline int query(int k,int l,int r){
if(a[k].l>=l&&a[k].r<=r)
return a[k].minl;
int mid=(a[k].l+a[k].r)>>1;
int x=INF;
if(r>mid)
x=min(x,query(k<<1|1,l,r));
if(l<=mid)
x=min(x,query(k<<1,l,r));
return x;
}
inline int work(int x,int h){
int i;
for(i=20;i>=0;i--){
if(val[dp[x][i]]>h)
x=dp[x][i];
}
return query(1,in[x],out[x]);
}
//inline char nc() {
// static char buf [100000],*p1=buf,*p2=buf;
// return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
//}
//inline int read(){
// static char c=nc(); int x=0,f=1;
// for(;c>'9'||c<'0';c=nc()) if(c=='-') f=-1;
// for(;c<='9'&&c>='0';c=nc()) x=(x<<3)+(x<<1)+c-48;
// return x*f;
//}
inline int read() {
int x=0;
char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0', c=getchar();
return x;
}
inline void outt(int x){
if(x < 0) {putchar('-'); x = -x;}
if(x >= 10)outt(x / 10);
putchar(x % 10 + '0');
}
int main(void){
int n,m,i,x,y,z,h;
int T;
//scanf("%d",&T);
T=read();
while(T--){
//scanf("%d%d",&n,&m);
n=read();m=read();
N=n;
for(i=1;i<=n;i++){
v[i].clear();
w[i].clear();
}
for(i=1;i<=2*n;i++){
kv[i].clear();
val[i]=0;
}
for(i=1;i<=m;i++){
//scanf("%d%d%d%d",&x,&y,&z,&h);
x=read();y=read();z=read();h=read();
edge[i].x=x;edge[i].y=y;edge[i].dep=h;
v[x].push_back(y);
w[x].push_back(z);
v[y].push_back(x);
w[y].push_back(z);
}
sort(edge+1,edge+m+1,cmp);
dijkstra(1);
for(i=1;i<=2*n;i++)
pre[i]=i;
int tot=n;
int s=2*n-1;
for(i=1;i<=m;i++){
int fx=find(edge[i].x);
int fy=find(edge[i].y);
if(fx!=fy){
pre[fx]=pre[fy]=++tot;
kv[tot].push_back(fx);
kv[tot].push_back(fy);
val[tot]=edge[i].dep;
}
if(tot==2*n-1)
break;
}
cnt=0;
dfs(s);
init();
build(1,1,2*n-1);
int q;
long long lastans=0,K,S,v,p;
//scanf("%d%lld%lld",&q,&K,&S);
q=read();K=read();S=read();
for(i=1;i<=q;i++){
//scanf("%lld%lld",&v,&p);
v=read();p=read();
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
//cout<<v<<" "<<p<<"\n";
lastans=work(v,p);
//printf("%lld\n",lastans);
outt(lastans);
putchar('\n');
}
}
return 0;
}