有N个点,M条无向虚边(边还未连接上去),Q组询问,询问格式如下:
对于第一个询问输入2个数L1,H1,表示你要用满足权值L1<=Ai<=H1的所有边来连接点使得能互相通达的点的数量最多。在此条件下,输出最小的权值和C1.
对于第i个询问(1<i<=q),输入2个数Li’,Hi’, Li = Li’-lastans, Hi = Hi’-lastans;(当i为1是lastans = 0)
N<=1000, M<=100000, Q<=1000000),输入2个数Li’,Hi’,其中Li=li’+c(i-1)
题解
双向链表写错了…线段树写成O(n)了,改蠢我了…
这题直接说做法吧,首先把边从大到小排序,每次加一条边,然后如果形成了环,就把环上最大的边删去(最小生成树),这个因为n只有1000所以可以暴力找,否则需要动态树。假设加入的边边权为vi,当查询xi,vi时,答案就是生成树中边权为在xi…vi之间的边的和,用线段树就可以了,但是这题强制在线,所以用可持久化线段树
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> int Int(){ char ch; int tmp = 0; while (ch = getchar()) if (ch >= '0' && ch <= '9') break; for (; ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0'; return tmp; } using namespace std; const int maxn = 1100, maxm = 110000, maxw = 1000100; int n, m; struct Tedge{ int x, y, v; }edge[maxm]; void init(){ n = Int(), m = Int(); for (int i = 0; i < m; i ++) edge[i].x = Int(), edge[i].y = Int(), edge[i].v = Int(); } int now[maxn], son[maxm * 2], pre[maxm * 2], v[maxm * 2]; bool cmp(Tedge a, Tedge b){ return a.v > b.v; } int tot, next[maxm * 2]; inline void cc(int a, int b, int c){ pre[++ tot] = now[a];next[now[a]] = tot; next[tot] = 0; now[a] = tot; son[tot] = b; v[tot] = c; } inline void make(int a, int b, int c){cc(a, b, c); cc(b, a, c); } inline void del(int x, int p){ if (now[x] == p) now[x] = pre[p]; next[pre[p]] = next[p]; pre[next[p]] = pre[p]; } struct segment{ struct node{ int sum; node *ls, *rs; void clear(){ ls = rs = 0, sum = 0; } void updata(){ sum = (ls?ls->sum:0) + (rs?rs->sum:0); } }*root[maxw], t[maxw * 10]; int tot; void build(node *&p, int l, int r){ p = newnode(); int mid = (l + r) / 2; if (l == r) return; build(p->ls, l, mid); build(p->rs, mid + 1, r); } void modify(node *last, node *&p, int l, int r, int x, int add){ p = newnode(); *p = *last; if (l == r){ p->sum += add; return; } int mid = (l + r) >> 1; if (x <= mid) modify(last->ls, p->ls, l, mid, x, add); else modify(last->rs, p->rs, mid + 1, r, x, add); p->updata(); } void clear(){ memset(root, 0, sizeof(root)); tot = 0; build(root[edge[0].v + 1], 1, edge[0].v); } node *newnode(){ t[++tot].clear(); return &t[tot]; } void modify(int x, int y, int add){ if (root[x]){ root[0] = newnode(), modify(root[x], root[0], 1, edge[0].v, y, add); root[x] = root[0]; } else modify(root[x + 1], root[x], 1, edge[0].v, y, add); } int query(node *p, int l, int r, int x, int y){ // cout <<l <<' ' <<r <<' ' <<x <<' ' <<y <<endl; if (p->sum == 0) return 0; if (l == x && r == y) return p->sum; int mid = (l + r) >> 1; if (mid >= y) return query(p->ls, l, mid, x, y); else if (mid < x) return query(p->rs, mid + 1, r, x, y); return query(p->ls, l, mid, x, mid) + query(p->rs, mid + 1, r, mid + 1, y); } int query(int x, int a, int b){ if (b > edge[0].v) b = edge[0].v; if (a > edge[0].v) return 0; // cout <<x <<' ' <<a <<' ' <<b <<endl; return query(root[a], 1, edge[0].v, a, b); } }seg; void find(int vv, int x, int y){ static int h[maxn]; int tt = 0, ww = 1; h[1] = x; static int frm[maxn]; memset(frm, 0, sizeof(frm)); while (tt ++ != ww){ for (int p = now[h[tt]]; p; p = pre[p]) if (!frm[son[p]] && son[p] != x) h[++ ww] = son[p], frm[son[p]] = p; if (frm[y]) break; } if (!frm[y]) return; Tedge t; int maxv = 0; for (int i = y; i != x; i = son[frm[i] ^ 1]) if (v[frm[i]] > maxv){ t.x = son[frm[i] ^ 1], t.y = i; t.v = (frm[i] ^ 1); maxv = v[frm[i]]; } del(t.x, t.v ^ 1), del(t.y, t.v); seg.modify(vv, maxv, -maxv); } inline void write(int x){if (!x) return;write(x/10); putchar(x%10+'0');} void work(){ sort(edge, edge + m, cmp); tot = 1; seg.clear(); memset(now, 0, sizeof(now)); // memset(next, 0, sizeof(next)); int j = 0; for (int i = 0; i < m; i = j){ int sum = 0; for (j = i; edge[j].v == edge[i].v; j ++){ int x = edge[j].x, y = edge[j].y; find(edge[j].v, x, y); make(edge[j].x, edge[j].y, edge[j].v); sum += edge[j].v; } seg.modify(edge[i].v, edge[i].v, sum); for (int k = edge[i].v - 1; k > edge[j].v; k --) seg.root[k] = seg.root[edge[i].v]; } int q = Int(), last = 0; for (int i = 1; i <= q; i ++){ int a = Int() - last, b = Int() - last; last = seg.query(b, a, b); if (last) write(last); else putchar('0'); putchar('\n'); } } int main(){ int T = Int(); while (T -- ) init(), work(); return 0; }