codeforces 342E Xenia and Tree

49 篇文章 0 订阅
18 篇文章 0 订阅

http://www.elijahqi.win/2018/03/04/codeforces-342e-xenia-and-tree/
题目描述

Xenia the programmer has a tree consisting of

n
n nodes. We will consider the tree nodes indexed from 1 to

n
n . We will also consider the first node to be initially painted red, and the other nodes — to be painted blue.

The distance between two tree nodes

v
v and

u
u is the number of edges in the shortest path between

v
v and

u
u .

Xenia needs to learn how to quickly execute queries of two types:

paint a specified blue node in red;
calculate which red node is the closest to the given one and print the shortest distance to the closest red node.
Your task is to write a program which will execute the described queries.

输入输出格式

输入格式:
The first line contains two integers

n
n and

m
m

(2<=n<=10^{5},1<=m<=10^{5})
(2<=n<=105,1<=m<=105) — the number of nodes in the tree and the number of queries. Next

n-1
n−1 lines contain the tree edges, the

i
i -th line contains a pair of integers

a_{i},b_{i}
ai​,bi​

(1<=a_{i},b_{i}<=n,a_{i}≠b_{i})
(1<=ai​,bi​<=n,ai​≠bi​) — an edge of the tree.

Next

m
m lines contain queries. Each query is specified as a pair of integers

t_{i},v_{i}
ti​,vi​

(1<=t_{i}<=2,1<=v_{i}<=n)
(1<=ti​<=2,1<=vi​<=n) . If

t_{i}=1
ti​=1 , then as a reply to the query we need to paint a blue node

v_{i}
vi​ in red. If

t_{i}=2
ti​=2 , then we should reply to the query by printing the shortest distance from some red node to node

v_{i}
vi​ .

It is guaranteed that the given graph is a tree and that all queries are correct.

输出格式:
For each second type query print the reply in a single line.

输入输出样例

输入样例#1: 复制

5 4
1 2
2 3
2 4
4 5
2 1
2 5
1 2
2 5
输出样例#1: 复制

0
3
2
每sqrt(n)个就暴力做一遍 比较最小 如果到达sqrt(n)了 就全局bfs一下将这些信息更新到每个点里面 保证每次询问的都是sqrt(n)的内容 另外这里的lca我选择了rmq的离线版本 o(1)回答询问 否则复杂度可能变成n*sqrt(n)*log(n)

#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 110000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int cnt,h[N],n,m,nn,qq[N],top,mn[N<<1][20],dep[N],dis[N],Log[N<<1],pos[N],num;
struct node{
    int y,next;
}data[N<<1];
inline void dfs(int x,int fa){
    mn[++cnt][0]=x;pos[x]=cnt;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa) continue;
        dep[y]=dep[x]+1;dis[y]=dep[y];dfs(y,x);mn[++cnt][0]=x;
    }
}
inline void init(){
    int t=Log[cnt];
    for (int j=1;j<=t;++j)
        for (int i=1;i+(1<<j)-1<=cnt;++i)
            if (dep[mn[i][j-1]]<dep[mn[i+(1<<j-1)][j-1]])
                mn[i][j]=mn[i][j-1];else mn[i][j]=mn[i+(1<<j-1)][j-1];
}
inline int lca(int x,int y){
    x=pos[x];y=pos[y];if (x>y) swap(x,y);int t=Log[y-x+1];
    return dep[mn[x][t]]<dep[mn[y-(1<<t)+1][t]]?mn[x][t]:mn[y-(1<<t)+1][t];
}
inline int calc(int x,int y){return dep[x]+dep[y]-(dep[lca(x,y)]<<1);}
inline void bfs(){
    queue<int>q;for (int i=1;i<=top;++i) q.push(qq[i]),dis[qq[i]]=0;top=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        for (int i=h[x];i;i=data[i].next){
            int y=data[i].y;
            if (dis[x]+1<dis[y]) dis[y]=dis[x]+1,q.push(y);
        }
    }
}
int main(){
//  freopen("cf342e.in","r",stdin);
    n=read();m=read();nn=sqrt(n);Log[0]=-1;
    for (int i=1;i<=n<<1;++i) Log[i]=Log[i>>1]+1;
    for (int i=1;i<n;++i) {
        int x=read(),y=read();
        data[++num].y=y;data[num].next=h[x];h[x]=num;
        data[++num].y=x;data[num].next=h[y];h[y]=num;
    }dfs(1,0);init();cnt=0;
    //for (int i=1;i<=n;++i) printf("%d ",dis[i]);
//  printf("%d ",lca(2,5)); printf("%d ",lca(3,2)); printf("%d \n",lca(8,9));
    while(m--){
        int op=read(),x=read();
        if (op==1) {if (top==nn) bfs();qq[++top]=x;continue;}
        int tmp=inf;for (int i=1;i<=top;++i) tmp=min(tmp,calc(qq[i],x));
        tmp=min(tmp,dis[x]);printf("%d\n",tmp);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值