离家出走

  

离家出走


时间限制: 2000 ms         内存限制: 256M

【题目描述】

企鹅豆豆考试爆零了

心态爆炸的他准备离家出走

贫穷的企鹅国有 N 座城市

一开始城市之间没有道路连接不能通行

随着时间推移,一些道路逐渐建立

但由于国家财力实在不足

所以随时随地任意两座城市最多只有一条路径可以互相到达

每次豆豆考试爆炸,他都想从考场里跑到离考场最远的一个城市去

当然豆豆每次都会想知道

最远的且可以到达的城市离考场所在城市有多远?

奇妙的事情是,企鹅国的每一条道路长度都是 1

【输入】

第一行一个整数 type,表示数据类型。

接下来第二行两个整数 N,Q,表示城市个数和事件个数。

接下来 Q 行,先读入一个整数 op,表示事件类型。

如果 op=1,那么接着有两个整数 u,v

表示城市 u 和城市 v 之间建立了一条新的道路。

如果 op=2,那么接着有一个整数 u

表示这次考试的考场在城市 u

豆豆想知道最远的城市离考场有多远。

如果 type=1,令上一次 op=2 时的答案为 lastans,

那么对于输入的每一个 u 或者 v 都需要异或上 lastans

(lastans 初始为 0。)

如果 type=0,那么不需要进行其余额外操作。

【输出】

对于每次 op=2 的询问

输出一行一个整数表示离考场最远的城市距离考场的距离。

【输入样例】

0
5 10
1 4 5
2 3
2 5
2 1
1 5 3
1 1 4
2 3
2 5
1 5 2
2 1

【输出样例】

0
1 
0
3
2
3

【提示】

对于 20%的输入数据:N≤5000,Q≤10000。

对于 50%的输入数据:N≤100000,Q≤200000。

对于另外 20%的输入数据:type=0。

对 100%的输入数据:N≤300000,Q≤500000,

道路的修建会满足,随时随地图中不存在环。


毒瘤...

反正就是个并查集 + 倍增lca + 启发式合并,复杂度Qlog²n

有个性质:合并两个树,新的直径端点一定在原直径端点上。

还有个:树上一点能到达的最远点一定是直径端点

然后合并的时候启发式合并,更新小树上的dis,fa

同时更新大树根上记录的直径端点。

A了但是这数据有毒,暴力合并比正解还快...没有一条链数据来卡。

  1 #include <cstdio>
  2 #include <algorithm>
  3 const int N = 400010;
  4 
  5 struct Edge {
  6     int v, nex;
  7 }edge[N << 1]; int top;
  8 int dis[N], siz[N], fa[N][20], l[N], r[N], e[N];
  9 int ufs[N], lm;
 10 inline void init(const int &n) {
 11     lm = 19;
 12     while((1 << lm) > n) {
 13         lm--;
 14     }
 15     for(int i = 1; i <= n; i++) {
 16         ufs[i] = i;
 17         siz[i] = 1;
 18         dis[i] = 1; /// error : 0
 19         l[i] = r[i] = i; /// error : i
 20     }
 21     return;
 22 }
 23 inline void add(int x, int y) {
 24     top++;
 25     edge[top].v = y;
 26     edge[top].nex = e[x];
 27     e[x] = top;
 28     return;
 29 }
 30 inline int find(int x) {
 31     if(ufs[x] == x) {
 32         return x;
 33     }
 34     return ufs[x] = find(ufs[x]);
 35 }
 36 void DFS(int x, int d, int f) { /// error : NO f
 37     dis[x] = d;
 38     for(int i = 1; i <= lm; i++) {
 39         fa[x][i] = fa[fa[x][i - 1]][i - 1];
 40     }
 41     for(int i = e[x]; i; i = edge[i].nex) {
 42         int y = edge[i].v;
 43         if(y == f) {
 44             continue;
 45         }
 46         fa[y][0] = x;
 47         DFS(y, d + 1, x);
 48     }
 49     return;
 50 }
 51 inline int lca(int x, int y) {
 52     if(dis[x] > dis[y]) {
 53         std::swap(x, y);
 54     }
 55     int i = lm;
 56     while(i >= 0 && dis[x] != dis[y]) {
 57         if(dis[x] <= dis[fa[y][i]]) {
 58             y = fa[y][i];
 59         }
 60         i--;
 61     }
 62     if(x == y) {
 63         return x;
 64     }
 65     i = lm;
 66     while(i >= 0 && fa[x][0] != fa[y][0]) {
 67         if(fa[x][i] != fa[y][i]) {
 68             x = fa[x][i];
 69             y = fa[y][i];
 70         }
 71         i--;
 72     }
 73     return fa[x][0];
 74 }
 75 inline int dist(int x, int y) {
 76     return dis[x] + dis[y] - (dis[lca(x, y)] << 1);
 77 }
 78 inline void merge(int x, int y) {
 79     int tx = find(x);
 80     int ty = find(y);
 81     if(siz[tx] < siz[ty]) {
 82         std::swap(x, y);
 83         std::swap(tx, ty);
 84     }
 85     /// x >= y
 86     fa[y][0] = x;
 87     DFS(y, dis[x] + 1, x);
 88     siz[tx] += siz[ty];
 89 
 90     int A = l[tx], B = l[ty];
 91     int C = r[tx], D = r[ty];
 92     int len = dist(A, C);
 93     int a = A, b = C;
 94     int t = dist(A, B);
 95     if(len < t) {
 96         len = t;
 97         b = B;
 98     }
 99     t = dist(A, D);
100     if(len < t) {
101         len = t;
102         b = D;
103     }
104     t = dist(C, B);
105     if(len < t) {
106         len = t;
107         a = C;
108         b = B;
109     }
110     t = dist(B, D);
111     if(len < t) {
112         len = t;
113         a = B;
114         b = D;
115     }
116     t = dist(C, D);
117     if(len < t) {
118         a = C;
119         b = D;
120     }
121     l[tx] = a;
122     r[tx] = b;
123     add(x, y);
124     add(y, x);
125     ufs[ty] = tx;
126     return;
127 }
128 inline int ask(int x) {
129     int L = l[find(x)], R = r[find(x)];
130     return std::max(dist(x, L), dist(x, R));
131 }
132 int main() {
133     int k;
134     int n, T;
135     scanf("%d", &k);
136     scanf("%d%d", &n, &T);
137     init(n);
138     int f, x, y, lastans = 0;
139     while(T--) {
140         scanf("%d", &f);
141         if(f == 1) {
142             scanf("%d%d", &x, &y);
143             if(k) {
144                 x ^= lastans;
145                 y ^= lastans;
146             }
147             if(find(x) != find(y)) {
148                 merge(x, y);
149             }
150         }
151         else {
152             scanf("%d", &x);
153             if(k) {
154                 x ^= lastans;
155             }
156             lastans = ask(x);
157             printf("%d\n", lastans);
158         }
159     }
160     return 0;
161 }
AC代码

 

转载于:https://www.cnblogs.com/huyufeifei/p/9350580.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值