Dash Speed

来源:互联网 发布:青山知可子女机械人511 编辑:程序博客网 时间:2024/05/18 03:46

题目描述
一棵有n个点的树 每条边有限制liri 只有当询问满足liqiri时才能通过这条边
求对于每个询问 最多可以在一条简单路径上通过多少条边

测试点编号 n m 约定 1 5 5 无 2 20 20 无 3 50000 50000 li=1,树为一条链 4 70000 70000 li=1,树为一条链 5 50000 50000 树为一条链 6 70000 70000 树为一条链 7 50000 50000 li=1 8 70000 70000 li=1 9 50000 50000 无 10 70000 70000 无

算法1

对于每个询问从一个点开始DFS 过程中更新ans即可
O(n^2)

算法2

li=1且树为一条链
可以把询问和边都按限制从大到小排序
模拟Kruskal求最小生成树 维护每个联通块的大小
询问的答案即为最大的联通块的大小
O(n*log(n))

算法3

树为一条链
询问其实就是求完全包含qi的边构成的最大联通块
把一条边的限制拆成两个 看成在li时间把i点标记 然后在ri+1的时间取消i点的标记
用线段树维护一个时刻的最大由打了标记的点构成的联通块 它的大小即为询问的答案
这是一个常规的线段树问题
每个线段树的节点维护区间内前后缀以及当前区间的最大联通块即可
O(n*log(n))

算法4

li=1
考虑把算法2中的链引申为树
链上一个联通块的最长链就是由左端点到右端点 因此就是联通块的大小
而树的合并时就要分类讨论了
并查集中每个联通块记录左端点Li和右端点Ri
那么显然合并后的联通块的两端点必定在合并前两个联通块的四个端点中
而这四个点有C24=6种情况
对于每种情况求两点间距离取最大值即可
O(n*log(n))

算法5

考虑分治
对于分治的一个区间[L,R] 把所有完全包含这个区间的边都加入
用算法4的方法合并
然后分治两个子区间
这样是要撤销合并操作的 所以并查集要按秩合并
合并时还要存储被合并的并查集的各种信息 以及当前ans
分治完后全部还原 然后返回上一区间
在预处理时为了方便 在线段树上把边插入对应区间 分治时直接读取即可
还要把询问插入对应的点中 在分治到一个点时回答所有询问
O(n*log(n)^2)
一个小优化 如果当前区间没有任何询问 就不需要向下分治了
我用的是树链剖分求LCA 写起来方便一些

#include<bits/stdc++.h>using namespace std;#define N 70010#define Lc p<<1#define Rc p<<1|1void rd(int &x){    char c;x=0;    while (c=getchar(),c<48);    do x=(x<<3)+(x<<1)+(c^48);    while (c=getchar(),c>=48);}struct edge{    int nxt,t,l,r;}e[N<<1];int tot,head[N];void add_edge(int x,int y,int l,int r){    e[tot]=(edge){head[x],y,l,r};    head[x]=tot++;    e[tot]=(edge){head[y],x,l,r};    head[y]=tot++;}struct road{    int x,y,l,r;}E[N];struct query{    int a,id;}Q[N];struct cpy{    int x,y,l,r,siz,len;}cop[N];int dep[N],siz[N],fa[N],son[N],top[N],ans[N],F[N],L[N],R[N],Len[N],res,rec;vector<int>B[N];int n,m;struct Segment_Tree{    vector<int>A[N<<2];    int sum[N<<2];    void add(int l,int r,int p,int x){        if (E[x].l<=l && E[x].r>=r){            A[p].push_back(x);            return;        }        int mid=(l+r)>>1;        if (E[x].r<=mid) add(l,mid,Lc,x);        else if (E[x].l>mid) add(mid+1,r,Rc,x);        else add(l,mid,Lc,x),add(mid+1,r,Rc,x);    }    void build(int l,int r,int p){        if (l==r){            sum[p]=B[l].size();            return;        }        int mid=(l+r)>>1;        build(l,mid,Lc);        build(mid+1,r,Rc);        sum[p]=sum[Lc]+sum[Rc];    }}T;void dfs(int x,int f){    dep[x]=dep[f]+1;    siz[x]=1;    fa[x]=f;    int i;    for (i=head[x];~i;i=e[i].nxt){        int to=e[i].t;        if (to==f) continue;        dfs(to,x);        siz[x]+=siz[to];        if (siz[to]>siz[son[x]]) son[x]=to;    }}void dfs1(int x,int tp){    top[x]=tp;    if (son[x]) dfs1(son[x],tp);    int i;    for (i=head[x];~i;i=e[i].nxt){        int to=e[i].t;        if (to==fa[x] || to==son[x]) continue;        dfs1(to,to);    }}int LCA(int x,int y){    while (top[x]!=top[y]){        if (dep[top[x]]<dep[top[y]]) swap(x,y);        x=fa[top[x]];    }    return dep[x]<dep[y]?x:y;}int get(int x){return F[x]==x?x:get(F[x]);}int Dis(int x,int y){return dep[x]+dep[y]-dep[LCA(x,y)]*2;}void merge(int x,int y){    int p=get(x),q=get(y);    if (p==q) return;    if (siz[p]<siz[q]) swap(p,q);    cop[++rec]=(cpy){p,q,L[p],R[p],siz[p],Len[p]};    F[q]=p;    siz[p]+=siz[q];    int x1=L[p],x2=R[p],x3=L[q],x4=R[q];    if (Len[q]>Len[p]){        Len[p]=Len[q];        L[p]=L[q];        R[p]=R[q];    }    int t;    t=Dis(x1,x3);    if (t>Len[p]){        Len[p]=t;        L[p]=x1;        R[p]=x3;    }    t=Dis(x1,x4);    if (t>Len[p]){        Len[p]=t;        L[p]=x1;        R[p]=x4;    }    t=Dis(x2,x3);    if (t>Len[p]){        Len[p]=t;        L[p]=x2;        R[p]=x3;    }    t=Dis(x2,x4);    if (t>Len[p]){        Len[p]=t;        L[p]=x2;        R[p]=x4;    }    res=max(res,Len[p]);}void work(int l,int r,int p){    if (!T.sum[p]) return;    int i,tmp=rec,tmp1=res;    for (i=0;i<T.A[p].size();i++){        int t=T.A[p][i];        merge(E[t].x,E[t].y);    }    if (l==r) for (i=0;i<B[l].size();i++) ans[B[l][i]]=res;    else{        int mid=(l+r)>>1;        work(l,mid,Lc);        work(mid+1,r,Rc);    }    while (rec>tmp){        int x=cop[rec].x,y=cop[rec].y;        F[y]=y;        L[x]=cop[rec].l;        R[x]=cop[rec].r;        siz[x]=cop[rec].siz;        Len[x]=cop[rec].len;        rec--;    }    res=tmp1;}void solve(){    int i;    dfs(1,0);    dfs1(1,1);    for (i=1;i<n;i++) T.add(1,n,1,i);    for (i=1;i<=n;i++) F[i]=L[i]=R[i]=i,siz[i]=1;    for (i=1;i<=m;i++) B[Q[i].a].push_back(Q[i].id);    T.build(1,n,1);    work(1,n,1);    for (i=1;i<=m;i++) printf("%d\n",ans[i]);}int main(){    memset(head,-1,sizeof(head));    rd(n),rd(m);    int i;    for (i=1;i<n;i++){        int x,y,l,r;        rd(x),rd(y),rd(l),rd(r);        add_edge(x,y,l,r);        E[i]=(road){x,y,l,r};    }    for (i=1;i<=m;i++) rd(Q[i].a),Q[i].id=i;    solve();    return 0;}

Date:2017/10/4
By CalvinJin