3514: Codechef MARCH14 GERALD07加強版
阿新 • • 發佈:2018-12-11
亂搞好題。。。
考慮加入一條邊,如果生成環,那麼把環上最早加入的邊刪去,答案就是用n-(編號在l到r的邊中刪去的邊的編號在1到l中的邊)。證明的話,yy一下吧。
想到這你可以激動的去寫一發樹上倍增,突然發現無法處理邊被替換
怎麼辦?上LCT。
作為一名(並不)熟練的NOIP選手,LCT+主席樹這種東西要在1小時1天內寫完。
程式碼:
/************************************************************** Problem: 3514 User: sckalrter Language: C++ Result: Accepted Time:36228 ms Memory:64184 kb ****************************************************************/ #include<bits/stdc++.h> #define inf 1e9 using namespace std; const int N=4e5+5; int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int ch[N][2],fa[N],mn[N],val[N],st[N],n,m,k,tp,s[N]; struct Edg{ int pre,poi; }e[N]; struct Tre{ int l,r,a; }tree[N*10]; int root[N],rt=0; bool rev[N]; bool isroot(int x){ return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x); } void update(int x){ int l=ch[x][0],r=ch[x][1]; mn[x]=x; if (val[mn[l]]<val[mn[x]]) mn[x]=mn[l]; if (val[mn[r]]<val[mn[x]]) mn[x]=mn[r]; } void down(int x){ int l=ch[x][0],r=ch[x][1]; if (rev[x]){ rev[l]^=1; rev[r]^=1; rev[x]^=1; swap(ch[x][0],ch[x][1]); } } void rotate(int x){ int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0; else l=1; r=l^1; if (!isroot(y)){ if (ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; } fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y; update(y); update(x); } void splay(int x){ int tot=0; st[++tot]=x; int y=x; for (int i=x;!isroot(i);i=fa[i]) st[++tot]=fa[i]; for (int i=tot;i>=1;i--) down(st[i]); while (!isroot(x)){ int y=fa[x],z=fa[fa[x]]; if (!isroot(y)){ if (ch[y][0]==x^ch[z][0]==y) rotate(x); else rotate(y); } rotate(x); } } void access(int x){ for (int y=0;x;y=x,x=fa[x]){ splay(x); ch[x][1]=y; update(x); } } void makeroot(int x){ access(x); splay(x); rev[x]^=1; } void link(int x,int y){ makeroot(x); fa[x]=y; } int findroot(int x){ access(x); splay(x); while (ch[x][0]) x=ch[x][0]; return x; } void cut(int x,int y){ makeroot(x); access(y); splay(y); fa[x]=ch[y][0]=0; } int query(int x,int y){ makeroot(x); access(y); splay(y); return mn[y]; } void insert(int &u,int v,int l,int r,int x){ u=++rt; tree[u]=tree[v]; tree[u].a++; int mid=(l+r)>>1; if (l==r) return; if (x<=mid) insert(tree[u].l,tree[v].l,l,mid,x); else insert(tree[u].r,tree[v].r,mid+1,r,x); } int ask(int u,int v,int l,int r,int ql,int qr){ if (ql<=l&&r<=qr) return tree[u].a-tree[v].a; int mid=(l+r)>>1,ans=0; if (ql<=mid) ans+=ask(tree[u].l,tree[v].l,l,mid,ql,qr); if (qr>mid) ans+=ask(tree[u].r,tree[v].r,mid+1,r,ql,qr); return ans; } void pre(){ int tot=n; for (int i=1;i<=m;i++){ int u=e[i].pre,v=e[i].poi; if (v==u){s[i]=i; continue;} if (findroot(u)==findroot(v)){ int p=query(u,v); int t=val[p]; s[i]=t; cut(e[t].pre,p); cut(e[t].poi,p); } tot++; mn[tot]=tot; val[tot]=i; link(tot,e[i].pre); link(tot,e[i].poi); } for (int i=1;i<=m;i++){ insert(root[i],root[i-1],0,m,s[i]); } } int main(){ n=read(),m=read(),k=read(),tp=read(); val[0]=inf; for (int i=1;i<=n;i++) mn[i]=i,val[i]=inf; for (int i=1;i<=m;i++){ e[i].pre=read(); e[i].poi=read(); } pre(); int ans=0; for (int i=1;i<=k;i++){ int l=read(),r=read(); if (tp) l^=ans,r^=ans; ans=n-ask(root[r],root[l-1],0,m,0,l-1); printf("%d\n",ans); } return 0; }