题意:中文题……不总结了……(好懒0-0)
土豪圈有一个习惯:从来不告诉别人自己到底有多少钱。但他们总是喜欢和其他土豪比较,来看看谁更土豪。于是每每几天,就会爆出一些关于土豪资产的消息,比如A土豪比B土豪多了3254万,C土豪比D土豪少2124万等等,从这些消息中也很容易推测出某两个土豪之间的资产关系。小破觉得和土豪交朋友是件非常愉快的事,但她想知道,某两个土豪,哪个更土豪。你能帮帮她么。
解法:并查集+向量偏移。
做这个题之前没接触过向量偏移……经典的食物链也没做过……看了这篇博客http://hi.baidu.com/tomspirit/item/d1f2a19b2aaf36d27a7f0158
对于本题来说,每个点到父亲节点的偏移量即为根节点比自己多了多少钱,则当查询a和b时,如果a和b在同一集中,delta[b] - delta[a]即为所求。
当新加入两个土豪的关系a比b多v时,c为a的父亲,d为b的父亲,向量表示如下:
已知c -> a, a -> b, d -> b,则c -> d = c -> a + v - d -> b, 即father[d] = c; delta[d] = delta[a] + v - delta[b];,d的根节点更新为c。
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define LL long long using namespace std; int father[100005]; int delta[100005]; int FIND(int a) { if(father[a] != a) { int temp = FIND(father[a]); delta[a] += delta[father[a]]; father[a] = temp; } return father[a]; } int main() { int n; while(~scanf("%d", &n)) { for(int i = 0; i <= n; i++) father[i] = i; memset(delta, 0, sizeof(delta)); for(int i = 0; i < n; i++) { int cmd; scanf("%d", &cmd); if(cmd == 1) { int a, b, v; scanf("%d%d%d", &a, &b, &v); int c = FIND(a), d = FIND(b); if(c != d) { father[d] = c; delta[d] = delta[a] + v - delta[b]; } } else { int a, b; scanf("%d%d", &a, &b); int c = FIND(a); int d = FIND(b); if(c != d) puts("?"); else { printf("%d ", delta[b] - delta[a]); } } } } return 0; }