Surface
Mandatory on-line version on Bzoj
Ideas
First of all, it can be determined that this type of Unicom block-related questions can be $lct$+ to resolve the persistent record
Using LCT to maintain spanning tree as the basis of algorithm
In particular, once in the past, follow the number order of the edges to sweep over the edges
If both ends of this edge are not in the same $lct$ Unicom block, the $link$
Otherwise $cut$ the lowest numbered edge on the path that is currently connected to two edges, and $link$
Record $ntr[i]$ indicates the number of edges $cut$ off before $link$ on the second case when the $i$ edge is triggered
If the first case is triggered, the $ntr[i]=0$
If self-loop, then $ntr[i]=i$
After this record, establish $ntr[i]$ 's chairman tree, each time in the position of $ntr[i]$ +1
For query $[l,r]$, $Ans =n-query (0,l-1,root[l-1],root[r]) $
This is due to the fact that each $ntr$ value is greater than or equal to $l$, and obviously they do not contribute to the answer (because it has been NTR)
Otherwise, they will connect two unicom blocks, but this side is not in the $[l,r]$ interval, so there are 1 of the contribution of the number of Unicom blocks
Code
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #define MP Make_ pairusing namespace Std;inline int read () {int Re=0,flag=1;char ch=getchar (); while (!isdigit (CH)) {if (ch== '-') flag=-1; Ch=getchar (); } while (IsDigit (CH)) re= (re<<1) + (re<<3) +ch-' 0 ', Ch=getchar (); return Re*flag;} int fa[400010],ch[400010][2],val[400010],minn[400010],rev[400010];void Update (int x) {minn[x]=x; if (Val[minn[x]]>val[minn[ch[x][0]]]) minn[x]=minn[ch[x][0]; if (Val[minn[x]]>val[minn[ch[x][1]]) minn[x]=minn[ch[x][1]];} int nroot (int x) {return (ch[fa[x]][0]==x) | | (ch[fa[x]][1]==x));} int get (int x) {return ch[fa[x]][1]==x;} void Pushrev (int x) {if (!x) return; Swap (ch[x][0],ch[x][1]); Rev[x]^=1;} void pushdown (int x) {if (!rev[x]) return; Pushrev (Ch[x][0]); Pushrev (ch[x][1]); rev[x]=0;} void push (int x) {if (!x) return; if (Nroot (x)) push (fa[x]); Pushdown (x);} void rotate (int x) { int F=fa[x],ff=fa[f],son=get (x), Nr=nroot (f);//cout<< "rotate" <<x<< "<<f<<" <&L t;ff<< ' <<son<< ' <<ch[x][0]<< ' <<ch[x][1]<< ' <<ch[f][0]< < ' <<ch[f][1]<< ' \ n '; CH[F][SON]=CH[X][SON^1]; if (Ch[f][son]) fa[ch[f][son]]=f; Fa[f]=x;ch[x][son^1]=f; FA[X]=FF; if (NR) ch[ff][ch[ff][1]==f]=x; Update (f); update (x);} void splay (int x) {//cout<< "splay" <<x<< ' \ n '; push (x); for (int f;nroot (x); rotate (x)) {f=fa[x]; if (Nroot (f)) rotate ((Get (x) ==get (f)) f:x); }}void access (int x) {//cout<< "access" <<x<< ' \ n '; for (int y=0;x;y=x,x=fa[x]) {splay (x); ch[x][1]=y;update (x);//cout<< "Do" <<x<< "<<fa[ x]<< ' <<y<< ' \ n '; }}void mroot (int x) {access (x); splay (x);p Ushrev (x);} void link (int u,int v) {mroot (u); fa[u]=v;} void Cut (int u,int v) {mroot (U); Access (v); splay (v); fa[u]=ch[v][0]=0;} int find (int u) {access (U); splay (U); while (Ch[u][0]) u=ch[u][0]; return u;} int query (int u,int v) {mroot (U); access (v); splay (v); return minn[v];} int lc[4000010],rc[4000010],seg[4000010],cnt;int ntr[400010],root[400010];int Insert (int l,int r,int pre,int pos) {int Cur=++cnt,mid= (l+r) >>1; lc[cur]=lc[pre];rc[cur]=rc[pre];seg[cur]=seg[pre]+1; if (l==r) return cur; if (Mid>=pos) Lc[cur]=insert (L,mid,lc[pre],pos); else Rc[cur]=insert (Mid+1,r,rc[pre],pos); return cur;} int query (int l,int r,int ql,int qr,int pre,int cur) {if (L>=QL&&R<=QR) return seg[cur]-seg[pre]; int mid= (L+R) >>1,re=0; if (MID>=QL) re+=query (L,mid,ql,qr,lc[pre],lc[cur]); if (MID<QR) re+=query (Mid+1,r,ql,qr,rc[pre],rc[cur]); return re;} int n,m,q;void init () {n=read (); M=read (); Q=read (); cnt=0; Memset (Lc,0,sizeof (LC)); memset (rc,0,sizeof (RC)); memset (seg,0,sizeof (SEG)); for (int i=1;i<=n;i++) fa[i]=ch[i][0]=ch[i][1]=0,minn[i]=i,val[i]=1e9,rev[i]=0; Val[0]=1e9;} Pair<int,int>e[200010];int Main () {int t=read (), i,t1,t2,tmp,w; while (t--) {init ();//cout<<n<< ' <<m<< ' <<q<< ' \ n '; for (i=1;i<=m;i++) {t1=read (); T2=read (); E[I]=MP (T1,T2);//cout<< "input" <<t1<< "<<t2<<" \ n "; if (t1==t2) {ntr[i]=i;continue;} if (Find (T1) ==find (T2)) {tmp=query (T1,T2); w=val[tmp]; Ntr[i]=w; Cut (Tmp,e[w].first); Cut (Tmp,e[w].second); } else ntr[i]=0;//cout<< "passed" <<ntr[i]<< ' \ n '; fa[n+i]=ch[n+i][0]=ch[n+i][1]=0; val[n+i]=i;minn[n+i]=n+i;rev[n+i]=0; Link (n+i,t1); link (n+i,t2); } for (i=1;i<=m;i++) Root[i]=insert (0,m,root[i-1],ntr[i]); for (i=1;i<=q;i++) {t1=read (); T2=read (); printf ("%d\n", N-query (0,m,0,t1-1,root[t1-1],root[t2])); } }}
[Bzoj3514][codechef GERALD07] Chef ans Graph Queries [lct+ Chairman Tree]