【GDOI2017模拟11.5】Dash Speed

来源:互联网 发布:linux卸载svn服务器 编辑:程序博客网 时间:2024/05/20 11:37

Description

给出n个点的一棵树,每条边有一个限制区间[l,r]。
给出m次询问,每次询问给出一个数x,求一条最长的所有边都满足l<=x<=r的路径。
n,m<=7*10^4

Solution

一开始看错数据范围,以为是7*10^5,虚的我。。。
然而没想到每次询问就是相当于保留所有l<=x<=r的边,求森林的直径
考虑分治(据说这也是cdq分治)
首先把每一条边放到所有它完全包含的分治区间中。
然后当我们做到当前区间时,把这个区间中的所有边加入森林中去。
回溯时候再把这些边删掉。
不过因为要兹瓷删边,所以我们的并查集不能路径压缩,只能按秩合并。。。
跑的慢死了。。。

Code

#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define rep(i,a) for(int i=last[a];i;i=next[i])using namespace std;const int N=7*1e4+5;struct note{int a,pa,pb,x,bz;}pr[N*20];int n,m,cnt,tot,ans,x,y,l,r,mx,mi[18],ln[N*2];int d[N],f[N],fir[N],dfn[N*2],g[N*2][18],p[N][2],q[N*20],rank[N],an[N];int t[N*2],next[N*2],last[N],la[N*4],ne[N*20],A[N*20],B[N*20];void add(int x,int y) {    t[++cnt]=y;next[cnt]=last[x];last[x]=cnt;}int max(int x,int y) {    if (x>y) return x;else return y;}void insert(int v,int l,int r,int x,int y,int a,int b) {    if (x<=l&&r<=y) {        A[++tot]=a;B[tot]=b;mx=max(mx,v);        ne[tot]=la[v];la[v]=tot;        return;    }    int m=(l+r)/2;    if (x<=m) insert(v*2,l,m,x,y,a,b);    if (y>m) insert(v*2+1,m+1,r,x,y,a,b);}void dfs(int x,int y) {    d[x]=d[y]+1;dfn[++tot]=x;fir[x]=tot;    rep(i,x) if (t[i]!=y) dfs(t[i],x),dfn[++tot]=x;}int get(int x) {    return f[x]?get(f[x]):x;}int lca(int x,int y) {    x=fir[x];y=fir[y];    if (x>y) swap(x,y);    int z=ln[y-x+1];    if (d[dfn[g[x][z]]]<d[dfn[g[y-mi[z]+1][z]]]) return dfn[g[x][z]];    else return dfn[g[y-mi[z]+1][z]];}int len(int x,int y) {    int z=lca(x,y);    return d[x]+d[y]-2*d[z];}void merge(int x,int &ans) {    int ax=get(A[x]),ay=get(B[x]);tot++;    int now[2],cnt;now[0]=p[ax][0];now[1]=p[ax][1];cnt=len(now[0],now[1]);    int dist=len(p[ay][0],p[ay][1]);    if (dist>cnt) cnt=dist,now[0]=p[ay][0],now[1]=p[ay][1];    fo(j,0,1) fo(k,0,1) {        dist=len(p[ax][j],p[ay][k]);        if (dist>cnt) cnt=dist,now[0]=p[ax][j],now[1]=p[ay][k];    }    if (rank[ay]<rank[ax]) {        pr[x].x=ay;pr[x].a=ax;        pr[x].pa=p[ax][0];pr[x].pb=p[ax][1];        p[ax][0]=now[0];p[ax][1]=now[1];        f[ay]=ax;    } else {        pr[x].x=ax;pr[x].a=ay;        pr[x].pa=p[ay][0];pr[x].pb=p[ay][1];        p[ay][0]=now[0];p[ay][1]=now[1];        f[ax]=ay;        if (rank[ax]==rank[ay]) rank[ay]++,pr[x].bz=1;    }    ans=max(ans,len(now[0],now[1]));}void del(int x) {    for(int i=la[x];i;i=ne[i]) q[++q[0]]=i;    while (q[0]) {        p[pr[q[q[0]]].a][0]=pr[q[q[0]]].pa;        p[pr[q[q[0]]].a][1]=pr[q[q[0]]].pb;        f[pr[q[q[0]]].x]=0;rank[pr[q[q[0]]].a]-=pr[q[q[0]]].bz;        q[0]--;    }}void work(int v,int l,int r,int ans) {    for(int i=la[v];i;i=ne[i]) merge(i,ans);    if (l==r) {        an[l]=ans;        del(v);        return;    }    int m=(l+r)/2;    work(v*2,l,m,ans);    work(v*2+1,m+1,r,ans);    del(v);}int main() {    freopen("speed.in","r",stdin);    freopen("speed.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n-1) {        scanf("%d%d%d%d",&x,&y,&l,&r);        add(x,y);add(y,x);        insert(1,1,n,l,r,x,y);    }    tot=0;dfs(1,0);mi[0]=1;    fo(i,1,tot) g[i][0]=i,ln[i]=log(i)/log(2);fo(i,1,17) mi[i]=mi[i-1]*2;    fo(j,1,17) fo(i,1,tot-mi[j]+1)         if (d[dfn[g[i][j-1]]]<d[dfn[g[i+mi[j-1]][j-1]]]) g[i][j]=g[i][j-1];        else g[i][j]=g[i+mi[j-1]][j-1];    fo(i,1,n) p[i][0]=p[i][1]=i;    work(1,1,n,0);    fo(i,1,m) scanf("%d",&x),printf("%d\n",an[x]);}
0 0
原创粉丝点击