题目大意:给你n个点m条边,再给你q个询问,查询边权在l~r之中,且覆盖点最多的边权和最小是多少 n<=1000 m<=100000 q<=1000000 w<=1000000 w是边权 强制在线
这题比较神,看了题想了一个小时都还没有思路,最后还是看了一下题解才弄懂
本质就是求边权在l~r内的最小生成树
先把所有的边按照边权从大到小排序,然后每次把边权相同的插入图中维护好最小生成树,再用一个可持久化线段树维护权值就OK了
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1011,maxm=100011,maxw=1000000;
inline void read(int &x){
char ch=getchar();x=0;
while (!isdigit(ch)) ch=getchar();
for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
struct Tedge{int a,b,c;}e[maxm];
int n,m,N;
void init(){
read(n); read(m);
for (int i=1;i<=m;++i) read(e[i].a),read(e[i].b),read(e[i].c);
}
struct Tsegt{
static const int maxn=10000011;
struct node{
node *lc,*rc; int s;
void clear(){lc=rc=0; s=0;}
void update(){int ls=lc?lc->s:0,rs=rc?rc->s:0; s=ls+rs;}
}*root[maxw*2+11],e[maxn];
int tot;
node *newnode(){e[tot].clear(); return e+(tot++);}
void build(node *p,int l,int r){
if (l==r) return; int mid=(l+r)>>1;
build(p->lc=newnode(),l,mid); build(p->rc=newnode(),mid+1,r);
}
void clear(){
tot=0; memset(root,0,sizeof(root)); root[N+1]=newnode(); build(root[N+1],1,N);
}
void ins(node *lp,node *p,int l,int r,int m,int add){
if (l==r && l==m) return p->s+=add*m,void();
int mid=(l+r)>>1; if (lp->lc) p->lc=lp->lc; if (lp->rc) p->rc=lp->rc;
if (m<=mid){
p->lc=newnode(); if (lp->lc) *p->lc=*lp->lc;
ins(lp->lc,p->lc,l,mid,m,add);
}else{
p->rc=newnode(); if (lp->rc) *p->rc=*lp->rc;
ins(lp->rc,p->rc,mid+1,r,m,add);
}
p->update();
}
void ins(int w,int m,int add){
if (!m) return;
if (root[w]) root[0]=newnode(),ins(root[w],root[0],1,N,m,add),root[w]=root[0];
else ins(root[w+1],root[w]=newnode(),1,N,m,add);
}
int Query(node *p,int l,int r,int fir,int las){
// if (!p) return 0;
if (l==fir && r==las) return p->s; int mid=(l+r)>>1;
if (las<=mid) return Query(p->lc,l,mid,fir,las);
if (fir>mid) return Query(p->rc,mid+1,r,fir,las);
return Query(p->lc,l,mid,fir,mid)+Query(p->rc,mid+1,r,mid+1,las);
}
int Query(int a,int b){if (b>N) b=N; return Query(root[a],1,N,a,b);}
}t;
int pre[maxm<<1],next[maxm<<1],son[maxm<<1],v[maxm<<1],now[maxn],tot=1;
inline void add(int a,int b,int c){
pre[++tot]=now[a]; next[now[a]]=tot; now[a]=tot; son[tot]=b; v[tot]=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];
}
inline void cc(int a,int b,int c){add(a,b,c); add(b,a,c);}
void clear(){tot=1; v[0]=0; memset(now,0,sizeof(now)); memset(next,0,sizeof(next));}
int find(Tedge e){
static int fp[maxn],fe[maxn],q[maxn];
int t=0,w=1; q[1]=e.a; memset(fp,0,sizeof(fp)); fp[e.a]=-1;
while (t++!=w) for (int p=now[q[t]];p;p=pre[p])
if (!fp[son[p]]) fp[q[++w]=son[p]]=q[t],fe[son[p]]=p;
Tedge ans; ans.c=0;
for (int x=e.b;fp[x]>0;x=fp[x])
if (v[fe[x]]>v[ans.c]) ans.a=fp[x],ans.b=x,ans.c=fe[x];
if (ans.c) del(ans.a,ans.c),del(ans.b,ans.c^1); cc(e.a,e.b,e.c); return v[ans.c];
}
inline bool cmp(Tedge a,Tedge b){return a.c>b.c;}
void prepare(){
sort(e+1,e+m+1,cmp); N=e[1].c; t.clear(); clear();
for (int i=N;i>e[1].c;--i) t.root[i]=t.root[i+1];
for (int i=1,j;i<=m;i=j){
for (j=i;e[j].c==e[i].c;++j){
t.ins(e[i].c,e[i].c,1);
t.ins(e[i].c,find(e[j]),-1);
}
if (j<=m) for (int k=e[i].c-1;k>e[j].c;--k) t.root[k]=t.root[e[i].c];
}
for (int i=e[m].c-1;i>0;--i) t.root[i]=t.root[e[m].c];
}
void work(){
prepare(); int q,a,b,la=0;
read(q); while (q--){
read(a); read(b);
a-=la; b-=la;
printf("%d\n",la=t.Query(a,b));
}
}
int main(){
int T; read(T); while (T--) init(),work();
return 0;
}