码迷,mamicode.com
首页 > 其他好文 > 详细

#4613. problem C

时间:2019-12-02 13:44:26      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:cto   nlog   clu   prim   ble   using   n+1   ret   nlogn   

题目描述

给一棵 $n$ 个点的树,每条边的边权为 $1$ 。

强制在线。

有 $m$ 次询问,每次询问给出 $u^{\prime}, v^{\prime}, w^{\prime}$ ,令 $u=\left(u^{\prime}+\text {lastans}\right) \% n+1, v= \left(v^{\prime}+\text {lastans}\right) \% n+1, w=\left(w^{\prime}+\text {lastans}\right) \% n$ , $lastans$ 为上一次询问的答案,初始时 $lastans=0$ 。

求有多少个点 $x$ 满足, $\min (\operatorname{dis}(x, u), \operatorname{dis}(x, v)) \leq w, \quad \operatorname{dis}(x, y)$ 等于 $x,y$ 在树上的距离

数据范围

$1 \leq n, m \leq 10^{5}, 1 \leq u, v, u^{\prime}, v^{\prime} \leq n, 0 \leq w, w^{\prime}<n$

题解

考场不应该想不出的题。

考虑分别对于 $u,v$ 求出 $dis(u,x) \le w$ , $dis(v,x) \le w$ 的点数,动态点分即可。

没想出如何去重,其实还挺简单的,就是 $dis(x,mid) \le w-\frac{dis(u,v)}{2}$ ,其中 $mid$ 是 $u,v$ 的中点,画个图理解一下吧。这个也可以动态点分。

为了方便,将边化成点,距离就都是偶数。

效率: $O(nlogn) \sim O(nlog^2n)$ 。

代码

#include <bits/stdc++.h>
using namespace std; const int N=2e5+5,M=N<<1;
int rt,o,n,m,son[N],sz[N],V[M],nx[M],hd[N],top[N],H,ax[M];
int a[N],d[N],e[N],f[N],up[N],c,tt,T[M],ans,s[N],ac[N][20];
bool vis[N];vector<int>g[M];
void add(int u,int v){
    V[++tt]=v;nx[tt]=hd[u];hd[u]=tt;
}
void dfs1(int x,int fa){
    ac[x][0]=f[x]=fa;d[x]=d[fa]+1;sz[x]=1;
    for (int i=1;ac[ac[x][i-1]][i-1];i++)
        ac[x][i]=ac[ac[x][i-1]][i-1];
    for (int i=hd[x];i;i=nx[i])
        if (V[i]!=fa){
            dfs1(V[i],x);sz[x]+=sz[V[i]];
            if (sz[s[x]]<sz[V[i]])
                s[x]=V[i];
        }
}
void dfs2(int x,int tp){
    top[x]=tp;
    if (s[x]) dfs2(s[x],tp);
    for (int i=hd[x];i;i=nx[i])
        if (V[i]!=f[x] && V[i]!=s[x])
            dfs2(V[i],V[i]);
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if (d[top[x]]<d[top[y]])
            swap(x,y);
        x=f[top[x]];
    }
    if (d[x]>d[y]) swap(x,y);return x;
}
int dis(int x,int y){
    return d[x]+d[y]-(d[lca(x,y)]<<1);
}
void change(int x){
    for (int v,i=x;up[i];i=up[i])
        v=dis(x,up[i]),
        ax[up[i]]=max(ax[up[i]],v),
        ax[i+H]=max(ax[i+H],v);
}
void update(int x){
    g[x][0]++;
    for (int v,i=x;up[i];i=up[i])
        v=dis(x,up[i]),g[up[i]][v]++,g[i+H][v]++;
}
void getrt(int x,int fa){
    sz[x]=1;son[x]=0;
    for (int i=hd[x];i;i=nx[i])
        if (V[i]!=fa && !vis[V[i]])
            getrt(V[i],x),sz[x]+=sz[V[i]],
            son[x]=max(son[x],sz[V[i]]);
    son[x]=max(son[x],o-sz[x]);
    if (son[x]<son[rt]) rt=x;
}
void work(int x,int fa){
    vis[x]=1;up[x]=fa;
    for (int i=hd[x];i;i=nx[i])
        if (!vis[V[i]])
            o=sz[V[i]],rt=0,
            getrt(V[i],x),work(rt,x);
}
void go(int x,int y,int w){
    ans+=w*g[x][min(y,ax[x])];
    for (int v,i=x;up[i];i=up[i]){
        v=dis(x,up[i]);
        if (v<=y)
            ans+=w*g[up[i]][min(y-v,ax[up[i]])],
            ans-=w*g[i+H][min(y-v,ax[i+H])];
    }
}
int main(){
    son[0]=1e9;scanf("%d%d",&n,&m);H=n;
    for (int x,y,i=1;i<n;i++)
        scanf("%d%d",&x,&y),H++,
        add(x,H),add(H,x),add(y,H),add(H,y);
    dfs1(1,0);dfs2(1,1);o=H;
    getrt(1,0);work(rt,0);tt=0;
    for (int i=1;i<=n;i++) change(i);
    for (int i=1;i<=H+H;i++)
        for (int j=0;j<=ax[i];j++)
            g[i].push_back(0);
    for (int i=1;i<=n;i++) update(i);
    for (int i=1;i<=H+H;i++)
        for (int j=1;j<=ax[i];j++)
            g[i][j]+=g[i][j-1];
    for (int u,v,w,l,x,y;m--;){
        scanf("%d%d%d",&u,&v,&w);
        u=(u+ans)%n+1;v=(v+ans)%n+1;
        w=(w+ans)%n*2;ans=0;go(u,w,1);go(v,w,1);
        l=lca(u,v);y=d[u]+d[v]-(d[l]<<1);
        if (d[u]>d[v]) swap(u,v);x=v;
        for (int i=19;~i;i--)
            if (d[ac[x][i]]>=d[l] && ((d[v]-d[ac[x][i]])<<1)<=y)
                x=ac[x][i];
        y>>=1;if (w>=y) go(x,w-y,-1);
        printf("%d\n",ans);
    }
    return 0;
}

 

#4613. problem C

标签:cto   nlog   clu   prim   ble   using   n+1   ret   nlogn   

原文地址:https://www.cnblogs.com/xjqxjq/p/11969889.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!