hdu-2419 Boring Game
http://acm.hdu.edu.cn/showproblem.php?pid=2419
给一个图,预分配点值。随后有三种操作,F u v查询与u联通部分大于等于v的最小的数,没有则返回0,U u v更新u的值为v,E u v删除u-v的边。
联通块可以用并查集解决,但是删边无法处理。因为没有加边,我们可以把整个操作过程反过来进行,就变成只有加边没有删边了。期间仔细维护各个值就好。
涉及边的删除,所以用set存边。查找最值可以用multi_set的lower_bound。并查集涉及集合合并,可以用s[a].insert(b.begin(),b.end()),实测效率和遍历b并Insert到a中几乎没差别,切记要让小集合向大集合合并!!!
#include <iostream> #include <cstring> #include <string> #include <queue> #include <vector> #include <map> #include <set> #include <stack> #include <cmath> #include <cstdio> #include <algorithm> #define LL int using namespace std; const LL N = 20004; multiset<int> g[N]; int n, m, q; LL val[N]; struct cmd { char e; LL k, v; cmd(char ee, LL kk, LL vv) { e = ee; k = kk; v = vv; } cmd() { } }; LL pre[N]; multiset<LL> s[N]; LL Find(LL x) { if (pre[x] == x)return x; return pre[x]=Find(pre[x]); } void mix(LL t1, LL t2) { LL pt1 = Find(t1), pt2 = Find(t2); if (pt1==pt2)return; if (s[pt1].size() > s[pt2].size()) swap(pt1, pt2); pre[pt1] = pt2; s[pt2].insert(s[pt1].begin(), s[pt1].end()); //for (multiset<LL>::iterator it = s[pt1].begin(); it != s[pt1].end(); it++) //s[pt2].insert(*it); s[pt1].clear(); } void upt(LL nod, LL v) { LL pt = Find(nod); //cout << pt << endl; s[pt].erase(s[pt].find(val[nod])); val[nod] = v; s[pt].insert(v); } LL fd(LL nod, LL v) { LL pt = Find(nod); multiset<LL>::iterator it= s[pt].lower_bound(v); if (it == s[pt].end())return 0; return *it; } cmd v[N * 30]; int main() { int cas = 1; while (scanf("%d%d%d",&n,&m,&q)!=EOF) { for (int i = 1; i <= n; i++) { LL num; s[i].clear(); g[i].clear(); scanf("%d", &num); val[i] = num; pre[i] = i; } for (int i = 1; i <= m; i++) { int fr, to; scanf("%d%d", &fr, &to); g[min(fr,to)].insert(max(fr,to)); //g[to].insert(fr); } LL siz = 0; while (q--) { char c[5]; LL t1, t2; scanf("%s %d %d", c, &t1, &t2); if (c[0] == 'E') { //g[t1].erase(t2); g[min(t1,t2)].erase(g[min(t1,t2)].find(max(t1,t2))); } if (c[0] == 'U') { LL temp = val[t1]; val[t1] = t2; t2 = temp; } v[siz++]=cmd(c[0], t1, t2); } for (int i = 1; i <= n; i++)s[i].insert(val[i]); for (int i = 1; i <= n; i++) { for (multiset<int>::iterator j = g[i].begin(); j != g[i].end(); j++) { int e = *j; mix(i, e); } } LL cnt = 0; double ans = 0; for (int i = siz-1; i >=0; i--) { cmd e = v[i]; //cout << e.e << ": " << e.k <<' '<< e.v << endl; if (e.e == 'E') { mix(e.k, e.v); } if (e.e == 'U') { upt(e.k, e.v); } if (e.e == 'F') { ans += fd(e.k, e.v); //cout << fd(e.k, e.v) << endl; cnt++; } } printf("Case %d: %.3f\n", cas++,ans*1.0 / cnt); } return 0; }