HDU - 5333
多维问题容易想到离线
从左到右,每次将\(max(u,v) \leq i\)的边加入,动态地用LCT维护一颗最大的生成树
每次插入如果产生环,将\(min(u,v)\)较大的边保留
满足最优性之后,加边删边的时,用树状数组维护边权\(\geq j\)的总数(即联通块减少的数量),就可以直接在树状数组上查询询问的区间
#include<cstdio>
#include<cctype>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
char IO;
int rd(){
int s=0,f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
const int N=2e5+10;
int n,m,q;
struct Edge{
int u,v;
int operator < (const Edge __) const {
return max(u,v)<max(__.u,__.v);
}
}E[N];
struct Node{
int x,id;
Node operator + (const Node __) const{
Node res;
res.x=min(x,__.x);
if(res.x==x) res.id=id;
else res.id=__.id;
return res;
}
}s[N],val[N];
struct Query{
int l,r,id;
bool operator < (const Query __) const{
return r<__.r;
}
}Q[N];
int Ans[N];
int eu[N],ev[N];
int stk[N],top;
int fa[N],son[N][2],rev[N];
inline int dir(int x){ return son[fa[x]][1]==x; }
inline int isroot(int x){ return !fa[x]||(son[fa[x]][0]!=x&&son[fa[x]][1]!=x); }
void Up(int u){
if(!u) return;
s[u]=val[u];
if(son[u][0]) s[u]=s[u]+s[son[u][0]];
if(son[u][1]) s[u]=s[u]+s[son[u][1]];
}
void Down(int u) {
if(!u || !rev[u]) return;
int t;
if(son[u][0]) {
t=son[u][0];
rev[t]^=1;
swap(son[t][0],son[t][1]);
}
if(son[u][1]) {
t=son[u][1];
rev[t]^=1;
swap(son[t][0],son[t][1]);
}
rev[u]=0;
}
void rotate(int u) {
int f=fa[u],ff=fa[f];
int d=dir(u);
fa[u]=ff; if(!isroot(f)) son[ff][dir(f)]=u;
son[f][d]=son[u][!d]; if(son[u][!d]) fa[son[u][!d]]=f;
fa[f]=u,son[u][!d]=f;
Up(f),Up(u),Up(ff);
}
void Splay(int x) {
static int stk[N],top=0;
int t=x;
while(!isroot(t)) stk[++top]=t,t=fa[t];
stk[++top]=t;
while(top) Down(stk[top--]);
while(!isroot(x)) {
int f=fa[x];
if(!isroot(f)) {
if(dir(x)^dir(f)) rotate(x);
else rotate(f);
}
rotate(x);
}
}
void Access(int x){ for(int t=0;x;t=x,x=fa[x]) Splay(x),son[x][1]=t,Up(x); }
void MakeRoot(int x) {
Access(x);
Splay(x);
rev[x]^=1;
swap(son[x][0],son[x][1]);
}
int GetRoot(int x) {
Access(x),Splay(x);
while(son[x][0]) Down(x),x=son[x][0];
Splay(x);
return x;
}
void Cut(int x,int y) {
MakeRoot(x),Access(y);
Splay(x);
if(son[x][1]!=y || fa[y]!=x) puts("WTF Cut?");
son[x][1]=fa[y]=0;
Up(x);
}
struct BIT{
int s[N];
void init(){ memset(s,0,sizeof s); }
void Add(int p,int x) {
while(p<=n) s[p]+=x,p+=p&-p;
}
int Que(int p) {
int res=0;
while(p) res+=s[p],p-=p&-p;
return res;
}
} B;
void Link(int x,int y,int w) {
if(GetRoot(x)==GetRoot(y)) {
MakeRoot(x),Access(y);
Splay(y);
Node t=s[y];
if(t.x>=w) return;
Cut(eu[t.id],t.id);
Cut(ev[t.id],t.id);
B.Add(t.x,-1);
stk[++top]=t.id;
}
MakeRoot(y);
int t=stk[top--];
eu[t]=x,ev[t]=y;
son[t][0]=son[t][1]=rev[t]=fa[t]=0,s[t]=val[t]=(Node){w,t};
fa[t]=x;
fa[y]=t;
B.Add(w,1);
}
int main(){
while(~scanf("%d%d%d",&n,&m,&q)) {
top=0;
rep(i,n+1,n*2) stk[++top]=i;
rep(i,1,n*2) fa[i]=son[i][0]=son[i][1]=rev[i]=0;
rep(i,1,n) s[i]=val[i]=(Node){(int)1e9,0};
rep(i,1,m) E[i].u=rd(),E[i].v=rd();
sort(E+1,E+m+1);
rep(i,1,q) Q[i].l=rd(),Q[i].r=rd(),Q[i].id=i;
sort(Q+1,Q+q+1);
int p1=1,p2=1;
B.init();
rep(i,1,n) {
while(p1<=m && E[p1].u<=i&&E[p1].v<=i) {
Link(E[p1].u,E[p1].v,min(E[p1].u,E[p1].v));
p1++;
}
while(p2<=q && Q[p2].r<=i) {
Ans[Q[p2].id]=B.Que(Q[p2].r)-B.Que(Q[p2].l-1);
p2++;
}
}
rep(i,1,q) printf("%d\n",n-Ans[i]);
}
}