洛谷4230:連環病原體——題解
阿新 • • 發佈:2018-05-29
TP tex int urn ios AD PE ostream --
https://www.luogu.org/problemnew/show/P4230
題面還是太難復制了。
樸素的搜環顯然是O(n^2)的。
但是可以發現搜環會反復的走過很多邊以及我們只需要一個環就夠了,所以方案之間是有重疊的。
(這時候yxd神犇看了眼題並且5s切了這道題。)
那麽還是固定枚舉左端點l,右端點r後移直到有環為止,則合法區間為[l,r][l,r+1]……[l,m],而且下一次的搜索顯然只需要l++就可以繼承上次的方案。
這個工作LCT即可勝任,顯然每個邊也就被遍歷過一次,所以是O(mlogn)的。
現在的問題是我們要如何計數,差分也許能給我們靈感。
對於[l,r][l,r+1]……[l,m]其中的每個區間都要+1,我們分成兩份,一份是提取所有區間的公共區間[l,r]用差分簡單做到存儲,另一份就是剩下的那些區間了,很顯然他們構成了等差數列。
顯然對數列我們差分無濟於事,考慮既然等差那就對公差差分。
比如3 2 1這樣的序列差分之後得到的就是3 -4 0 0 1,運算方法就是從右往左掃,記錄當前的公差sum,則s[i]=s[i+1]+sum
(orz一眼秒的rabbithu)
#include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cctype> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=4e5+5; const int M=2e5+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==‘-‘;ch=getchar();}while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int u,v; }e[M]; int m,r,rev[N],tr[N][2],fa[N],q[N]; inline bool get(int x){ return tr[fa[x]][1]==x; } inline bool isroot(int x){ if(!fa[x])return 1; return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x; } inline void push(int x){ if(!rev[x])return; swap(tr[x][0],tr[x][1]); if(tr[x][0])rev[tr[x][0]]^=1; if(tr[x][1])rev[tr[x][1]]^=1; rev[x]=0; } inline void rotate(int x){ int y=fa[x],z=fa[y],which=get(x); if(z&&!isroot(y))tr[z][tr[z][1]==y]=x; tr[y][which]=tr[x][which^1];fa[tr[y][which]]=y; fa[y]=x;tr[x][which^1]=y;fa[x]=z; } inline void splay(int x){ q[r=0]=x; for(int y=x;!isroot(y);y=fa[y])q[++r]=fa[y]; for(int i=r;i>=0;i--)push(q[i]); while(!isroot(x)){ if(!isroot(fa[x])) rotate(get(x)==get(fa[x])?fa[x]:x); rotate(x); } } inline void access(int x){ for(int y=0;x;y=x,x=fa[x]){ splay(x);tr[x][1]=y; if(y)fa[y]=x; } } inline int findroot(int x){ access(x);splay(x); while(push(x),tr[x][0])x=tr[x][0]; splay(x); return x; } inline void makeroot(int x){ access(x);splay(x);rev[x]^=1; } 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); tr[y][0]=0;fa[x]=0; } inline bool pan(int x,int y){ return findroot(x)==findroot(y); } ll s1[M],s2[M]; int main(){ m=read(); for(int i=1;i<=m;i++) e[i].u=read(),e[i].v=read(); int l=1,r=0; for(l;l<=m;l++){ bool ok=0; while(r<m){ r++; if(pan(e[r].u,e[r].v)){ok=1;break;} link(e[r].u,e[r].v); } if(ok){ s1[l]+=m-r+1; if(r<m)s1[r+1]-=m-r+1; s2[m]++;s2[r]+=r-m-1; if(r>1)s2[r-1]+=m-r; r--; } cut(e[l].u,e[l].v); } for(int i=1;i<=m;i++)s1[i]+=s1[i-1]; ll sum=0; for(int i=m;i>=1;i--){ sum+=s2[i]; s2[i]=s2[i+1]+sum; } for(int i=1;i<=m;i++)printf("%lld ",s1[i]+s2[i]); puts(""); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
洛谷4230:連環病原體——題解