有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;
}