[NOI2018] 归程

好久没更新博客了……

说说本题,预处理出所有的dis[x]表示1至x的长度,询问(v,p)的答案为min_{minLev(x,v)>p} dis[x]。建立关于lev从大到小的kruskal重构树,则minlev(x,v)=val[lca(x,v)]。

换句话说,任意在重构树v的某个祖先d有val[d]>p,可以用d子树(除开包含v节点的儿子子树)中所有叶节点的最小dis来更新答案。

注意到重构树是个二叉树。因此对于关于d查询的子树仍是一个完整的子树结构,设为d'(d的某个儿子)。如果令mindis[x]表示子树x的叶节点的最小dis值,则直接拿mindis[d']来更新。

若p始终为-inf,可以自顶向下预处理上述值,转换到一般情况就可以考虑树上主席树了。\(%^#\)&^&…… 这么写就成笑话了……注意到满足d[v]>p的点集中分布在v的祖先链的前缀,可以倍增找出那个分界点(深度最小的val<=p的点)然后取它的mindis……

1A了开心😊

参考实现

#include <bits/stdc++.h>
using namespace std;
const int N=8e5+10;

struct Enode {
    int u,v,a,l;
    bool operator<(const Enode&d) const{return a>d.a;}
};
struct Pnode {
    int key,dis;
    bool operator<(const Pnode&d) const{return dis>d.dis;}
};

int cnt,dis[N];
int head[N],to[N],len[N],lst[N];
bool vis[N];

void ins(int x,int y,int w) {
    to[++cnt]=y,len[cnt]=w,lst[cnt]=head[x],head[x]=cnt;
    to[++cnt]=x,len[cnt]=w,lst[cnt]=head[y],head[y]=cnt;
}
priority_queue<Pnode> pq;
void dijkstra() {
    memset(dis,0x3f,sizeof dis);
    pq.push((Pnode){1,dis[1]=0});
    while(pq.size()) {
        int x=pq.top().key; pq.pop();
        if(vis[x]) continue; vis[x]=1;
        for(int i=head[x]; i; i=lst[i]) if(dis[to[i]]>dis[x]+len[i]) 
            pq.push((Pnode){to[i],dis[to[i]]=dis[x]+len[i]});
    }
}

Enode a[N];
int n,m,rt[N],val[N],ch[N][2];
int fa[N][20];

int find(int x) {return rt[x]==x?x:rt[x]=find(rt[x]);}
void dfs(int x,int d) {
    for(int i=1; (1<<i)<=d; ++i) fa[x][i]=fa[fa[x][i-1]][i-1];
    if(x>n) {
        fa[ch[x][0]][0]=x; dfs(ch[x][0],d+1);
        fa[ch[x][1]][0]=x; dfs(ch[x][1],d+1);
        dis[x]=min(dis[ch[x][0]],dis[ch[x][1]]);
    }
}

void rebuild() {
    int tot=n;
    sort(a+1,a+m+1); 
    for(int i=1; i<=n; ++i) {
        memset(fa[i],0,sizeof fa[i]);
        rt[i]=i;
    }
    for(int i=1; i<=m; ++i) {
        int x=find(a[i].u),y=find(a[i].v);
        if(x!=y) {
            tot++; 
            memset(fa[tot],0,sizeof fa[tot]);
            rt[tot]=tot; val[tot]=a[i].a;
            rt[ch[tot][0]=x]=rt[ch[tot][1]=y]=tot;
        }
    }
    dfs(tot,1);
}
int query(int x,int p) {
    for(int i=19; ~i; --i) if(fa[x][i]&&val[fa[x][i]]>p) x=fa[x][i];
    return dis[x];
}


int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        cnt=0;
        memset(vis,0,sizeof vis);
        memset(head,0,sizeof head);
        scanf("%d%d",&n,&m);
        for(int i=1; i<=m; ++i) {
            scanf("%d%d%d%d",&a[i].u,&a[i].v,&a[i].l,&a[i].a);
            ins(a[i].u,a[i].v,a[i].l);
        }
        dijkstra();
        rebuild();
        int Q,K,S,lans=0;
        scanf("%d%d%d",&Q,&K,&S);
        for(int v,p; Q--; ) {
            scanf("%d%d",&v,&p);
            v=(v+K*lans-1)%n+1;
            p=(p+K*lans)%(S+1);
            lans=query(v,p);
            printf("%d\n",lans);
        }
    }
    return 0;
}
posted @ 2019-05-23 15:48  nosta  阅读(186)  评论(0编辑  收藏  举报