记录编号 89417 评测结果 AAAAAAAAAA
题目名称 [AHOI 2005] LANE 航线规划 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.555 s
提交时间 2014-03-02 16:00:00 内存使用 9.59 MiB
显示代码纯文本
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<vector>
  5. #include<algorithm>
  6. #include<iomanip>
  7. #include<map>
  8. #include<set>
  9. #include<cmath>
  10. #include<deque>
  11. using namespace std;
  12. const int SIZEN=30020,SIZEM=100100;
  13. class TARRAY{//改段求点的树状数组
  14. public:
  15. int n;
  16. int s[SIZEN];
  17. void clear(int x){n=x;memset(s,0,sizeof(s));}
  18. int lowbit(int x){return x&(-x);}
  19. void prefchange(int x,int t){
  20. for(int i=x;i>0;i-=lowbit(i)) s[i]+=t;
  21. }
  22. void change(int l,int r,int t){
  23. prefchange(r,t);
  24. prefchange(l-1,-t);
  25. }
  26. int nodeval(int x){
  27. int ans=0;
  28. for(int i=x;i<=n;i+=lowbit(i)) ans+=s[i];
  29. return ans;
  30. }
  31. };
  32. class REQUEST{
  33. public:
  34. int cmd;
  35. int a,b;
  36. };
  37. vector<REQUEST> req;//请求
  38. deque<int> ans;//答案
  39. vector<pair<int,int> > c[SIZEN];//邻接表,first是点,second是是否为桥(桥1否则0)
  40. int N,M;//N个点M条边
  41. int father[SIZEN]={0};
  42. TARRAY condep;
  43. int dfn[SIZEN]={0},low[SIZEN]={0};
  44. int numpst[SIZEN]={0};
  45. int color[SIZEN]={0};
  46. int ufs[SIZEN]={0};//并查集,维护该点所在的边双中最浅的点
  47. int dfslis[SIZEN*10]={0},dfslen=0;
  48. int first[SIZEN]={0};//在序列中首次出现的位置
  49. int ST[SIZEN*2][30]={0};//这个数组一定要是SIZEN*2......因为是DFS序列的长度
  50. int getdeep(int x){//x的深度
  51. return condep.nodeval(dfn[x]);
  52. }
  53. void STLCA_prepare(void){
  54. int m=floor(log(dfslen+0.0)/log(2.0));
  55. for(int i=1;i<=dfslen;i++) ST[i][0]=dfslis[i];
  56. for(int j=1;j<=m;j++){
  57. for(int i=1;i<=dfslen;i++){
  58. if(i+(1<<j)-1>dfslen) continue;
  59. int x=ST[i][j-1],y=ST[i+(1<<(j-1))][j-1];
  60. if(getdeep(x)<getdeep(y)) ST[i][j]=x;
  61. else ST[i][j]=y;
  62. }
  63. }
  64. }
  65. int STLCA(int a,int b){
  66. int l=first[a],r=first[b];
  67. if(l>r) swap(l,r);
  68. int m=floor(log(r-l+1.0)/log(2.0));
  69. int x=ST[l][m],y=ST[r-(1<<m)+1][m];
  70. return getdeep(x)<getdeep(y)?x:y;
  71. }
  72. int grand(int x){
  73. return ufs[x]==x?x:ufs[x]=grand(ufs[x]);
  74. }
  75. int bridgenum(int x,int y){//桥数等于缩点后树上的路径长
  76. int gx=grand(x),gy=grand(y);
  77. if(gx==gy) return 0;
  78. return getdeep(gx)+getdeep(gy)-2*getdeep(grand(STLCA(gx,gy)));
  79. }
  80. void addedge(int x,int y){//加边
  81. int gx=grand(x),gy=grand(y);
  82. if(gx==gy) return;
  83. int anc=grand(STLCA(gx,gy)),ad;//公共祖先
  84. ad=getdeep(anc);
  85. vector<int> st;
  86. for(int now=gx;now!=anc;now=grand(father[now])) st.push_back(now);
  87. for(int i=st.size()-1;i>=0;i--) condep.change(dfn[st[i]],dfn[st[i]]+numpst[st[i]]-1,ad-getdeep(st[i])),ufs[st[i]]=anc;
  88. st.clear();
  89. for(int now=gy;now!=anc;now=grand(father[now])) st.push_back(now);
  90. for(int i=st.size()-1;i>=0;i--) condep.change(dfn[st[i]],dfn[st[i]]+numpst[st[i]]-1,ad-getdeep(st[i])),ufs[st[i]]=anc;
  91. //分别把两条链上的点都提上去,因为此前已经将每个边双点的深度置为一样,因此它能正确地修改子树的深度
  92. }
  93. void offlinework(void){//离线处理
  94. for(int i=req.size()-1;i>=0;i--){
  95. if(req[i].cmd==1) ans.push_front(bridgenum(req[i].a,req[i].b));
  96. else if(req[i].cmd==0) addedge(req[i].a,req[i].b);
  97. }
  98. }
  99. void markDCC(int x,int sst,int dep){//对双连通分量进行标号,当前DCC中最浅的点是sst
  100. if(color[x]) return;
  101. color[x]=1;
  102. ufs[x]=sst;
  103. condep.change(dfn[x],dfn[x],dep);
  104. dfslis[++dfslen]=x;first[x]=dfslen;
  105. for(int i=0;i<c[x].size();i++){
  106. if(color[c[x][i].first]) continue;
  107. if(c[x][i].second) markDCC(c[x][i].first,c[x][i].first,dep+1);
  108. else markDCC(c[x][i].first,sst,dep);
  109. dfslis[++dfslen]=x;
  110. }
  111. }
  112. int timer=0;
  113. void Tarjan(int x){
  114. color[x]=-1;
  115. dfn[x]=low[x]=++timer;
  116. numpst[x]=1;
  117. for(int i=0;i<c[x].size();i++){
  118. int v=c[x][i].first;
  119. if(color[v]==0){
  120. father[v]=x;
  121. Tarjan(v);
  122. numpst[x]+=numpst[v];
  123. low[x]=min(low[v],low[x]);
  124. }
  125. else if(color[v]==-1&&v!=father[x]) low[x]=min(low[x],dfn[v]);
  126. if(dfn[x]<low[v]) c[x][i].second=1;//标记为桥
  127. }
  128. }
  129. set<pair<int,int> > edges;
  130. void init(void){
  131. scanf("%d%d",&N,&M);
  132. condep.clear(N);
  133. int u,v;
  134. pair<int,int> pr;
  135. for(int i=1;i<=M;i++){
  136. scanf("%d%d",&u,&v);
  137. if(u>v) swap(u,v);
  138. pr=make_pair(u,v);
  139. edges.insert(pr);
  140. }
  141. REQUEST nc;
  142. while(true){
  143. scanf("%d",&nc.cmd);
  144. if(nc.cmd==-1) break;
  145. scanf("%d%d",&nc.a,&nc.b);
  146. if(nc.a>nc.b) swap(nc.a,nc.b);
  147. req.push_back(nc);
  148. if(nc.cmd==0){//破坏一条边
  149. pr=make_pair(nc.a,nc.b);
  150. edges.erase(edges.find(pr));
  151. }
  152. }
  153. set<pair<int,int> >::iterator key;
  154. for(key=edges.begin();key!=edges.end();key++){
  155. u=key->first,v=key->second;
  156. c[u].push_back(make_pair(v,0));
  157. c[v].push_back(make_pair(u,0));
  158. }
  159. }
  160. int main(){
  161. freopen("lane.in","r",stdin);
  162. freopen("lane.out","w",stdout);
  163. init();//此时,c中存的就是所有询问之后的边信息
  164. Tarjan(1);
  165. memset(color,0,sizeof(color));
  166. markDCC(1,1,0);
  167. STLCA_prepare();
  168. offlinework();
  169. for(int i=0;i<ans.size();i++) printf("%d\n",ans[i]);
  170. return 0;
  171. }