1. 程式人生 > >2018.10.09 hdu5333 Undirected Graph(lct+)

2018.10.09 hdu5333 Undirected Graph(lct+)

傳送門 lct經典題。 我們把詢問按右端點排序。 這樣按照右端點值劃分詢問順序每次只會加入同一個右端點值那麼多的邊。 於是只需要處理左端點就行了。 如何處理? 對於不同的邊(u,v)(u,v),我們規定u>vu>v,然後按照vv排序。 貪心處理。 假設當前要加入一條邊。

  1. 加入後不會構成一個環,那麼直接用lctlctlinklink就行了。
  2. 加入後會構成一個環,那麼貪心去掉環上面編號最小的邊就行了。 相當於是維護一個動態最小生成森林。 跟最小生成樹的做法是一樣的。 但是如何統計答案呢? 我們維護當前加入了幾條有效邊。 這個可以用樹狀陣列維護。 每次l
    inklink
    時更新一下邊對應編號最後求單點值就行了。 程式碼:
#include<bits/stdc++.h>
#define N 300005
#define fi first
#define se second
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -
1 : *ib++; } inline int read() { char ch=nc(); int i=0; while(!isdigit(ch))ch=nc(); while(isdigit(ch)) {i=(i<<1)+(i<<3)+(ch^48); ch=nc();} return i; } inline void write(int x){ static int buf[50]; if(!x){putchar('0');return;} while(x)buf[++buf[0]]=x%10,x/=10; while(buf[0])putchar(buf[buf[
0]--]^48); } pair<int,int>e[N]; struct Q{int l,r,id;}qry[N]; int n,m,q,val[N],ans[N],tot; inline void swap(int&x,int&y){x^=y,y^=x,x^=y;} struct link_cut_tree{ int top,stk[N],fa[N],son[N][2],pos[N]; bool rev[N]; #define which(x) (x==son[fa[x]][1]) #define isroot(x) (!fa[x]||(x!=son[fa[x]][0]&&x!=son[fa[x]][1])) inline void pushdown(int p){ if(!rev[p])return; swap(son[p][0],son[p][1]),rev[p]^=1; if(son[p][0])rev[son[p][0]]^=1; if(son[p][1])rev[son[p][1]]^=1; } inline void pushup(int p){ pos[p]=p; if(son[p][0]&&val[pos[son[p][0]]]<val[pos[p]])pos[p]=pos[son[p][0]]; if(son[p][1]&&val[pos[son[p][1]]]<val[pos[p]])pos[p]=pos[son[p][1]]; } inline void rotate(int x){ int y=fa[x],z=fa[y],t=which(x); if(z&&!isroot(y))son[z][which(y)]=x; fa[y]=x,fa[x]=z,son[y][t]=son[x][t^1],son[x][t^1]=y; if(son[y][t])fa[son[y][t]]=y; pushup(y),pushup(x); } inline void splay(int x){ stk[top=1]=x; for(int i=x;!isroot(i);i=fa[i])stk[++top]=fa[i]; while(top)pushdown(stk[top--]); while(!isroot(x)){if(!isroot(fa[x]))rotate(which(x)==which(fa[x])?fa[x]:x);rotate(x);} } inline void access(int x){for(int y=0;x;x=fa[y=x])splay(x),son[x][1]=y,pushup(x);} inline void makeroot(int x){access(x),splay(x),rev[x]^=1,pushdown(x);} inline int findroot(int x){ access(x),splay(x); while(pushdown(x),son[x][0])x=son[x][0]; return splay(x),x; } inline void link(int x,int y){makeroot(x),fa[x]=y;} inline void cut(int x,int y){makeroot(x),access(y),splay(y),son[y][0]=fa[x]=0,pushup(y);} inline int query(int x,int y){return makeroot(x),access(y),splay(y),pos[y];} inline void clear(){memset(son,0,sizeof(son)),memset(fa,0,n+m+1<<2),memset(rev,false,n+m+1);for(int i=1;i<=n+m;++i)pos[i]=i;} }lct; int bit[N]; #define lowbit(x) (x&-x) inline void update(int x,int v){for(int i=x;i<=n;i+=lowbit(i))bit[i]+=v;} inline int query(int x){int ret=0;for(int i=x;i;i-=lowbit(i))ret+=bit[i];return ret;} inline bool cmp(Q a,Q b){return a.r<b.r;} int main(){ while(~scanf("%d",&n)){ m=read(),q=read(); for(int i=1;i<=n;++i)val[i]=0x3f3f3f3f,bit[i]=0; for(int i=1,u,v;i<=m;++i)u=read(),v=read(),e[i]=make_pair(max(u,v),min(u,v)); sort(e+1,e+m+1); for(int i=1;i<=q;++i)qry[i].l=read(),qry[i].r=read(),qry[i].id=i; sort(qry+1,qry+q+1,cmp); lct.clear(),tot=0; for(int i=1,j=1;i<=q;++i){ while(j<=m&&e[j].fi<=qry[i].r){ int u=e[j].fi,v=e[j].se; ++j,val[j+n]=v; if(lct.findroot(u)!=lct.findroot(v))lct.link(u,j+n),lct.link(j+n,v),update(v,1),++tot; else{ int p=lct.query(u,v); if(val[p]<val[j+n])lct.cut(e[p-n-1].fi,p),lct.cut(p,e[p-n-1].se),update(e[p-n-1].se,-1),lct.link(u,j+n),lct.link(j+n,v),update(v,1); } } ans[qry[i].id]=n-tot+query(qry[i].l-1); } for(int i=1;i<=q;++i)write(ans[i]),puts(""); } return 0; }