BZOJ 1969 树链剖分+Tarjan缩点

发现自己Tarjan的板子有错误.发现可以用Map直接删去边,Get.

听说std是双连通、LCA、并查集、离线思想、用BIT维护dfs序和并查集维护LCA的动态缩点的好题

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #define mp make_pair
 10 #define pa pair<int,int>
 11 #define pb push_back
 12 #define fi first
 13 #define se second
 14 using namespace std;
 15 inline void Get_Int(int &x)
 16 {
 17     x=0;  char ch=getchar(); int f=1;
 18     while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
 19     while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} x*=f;
 20 }
 21 inline void Put_Int(int x)
 22 {
 23     char ch[20]; int top=0;
 24     if (x==0) ch[++top]=‘0‘;
 25     while (x) ch[++top]=x%10+‘0‘,x/=10;
 26     while (top) putchar(ch[top--]); putchar(‘\n‘);
 27 }
 28 //===================================================
 29 const int Maxm=200100;
 30 const int Maxn=30100;
 31 const int Maxop=40100;
 32 struct EDGE{int to,next;}edge[Maxm];
 33 struct OP{int type,u,v;}Op[Maxop];
 34 int head[Maxn],siz[Maxn],father[Maxn],top[Maxn],dep[Maxn],num[Maxn],sum[Maxn<<2],clr[Maxn<<2];
 35 int Belong[Maxn],Low[Maxn],Dfn[Maxn],Ans[Maxn];
 36 int Stack[Maxn];
 37 int stamp,Stamp,cnt,scc,apex,Q,n,m,u,v;
 38 bool vis[Maxn];
 39 map<pa,bool> Edge;
 40 vector<pa> V;
 41 set <pa> S;
 42 inline void Add(int u,int v)
 43 {edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}
 44 inline int Max(int x,int y) {return x>y?x:y;}
 45 inline int Min(int x,int y) {return x>y?y:x;}
 46 inline void Build_G()
 47 {
 48     map<pa,bool>::iterator it;
 49     for (it=Edge.begin();it!=Edge.end();it++)
 50         if (it->se)
 51             Add(it->fi.fi,it->fi.se);
 52 }
 53 inline void Clear_G()
 54 {
 55     map<pa,bool>::iterator it;
 56     for (it=Edge.begin();it!=Edge.end();it++)
 57         if (it->se) it->se=false;
 58 }
 59 //=================================================
 60
 61 void Dfs1(int u)
 62 {
 63     vis[u]=true; siz[u]=1;
 64     for (int i=head[u];i!=-1;i=edge[i].next)
 65         if (!vis[edge[i].to])
 66         {
 67             father[edge[i].to]=u;
 68             dep[edge[i].to]=dep[u]+1;
 69             Dfs1(edge[i].to);
 70             siz[u]+=siz[edge[i].to];
 71         }
 72 }
 73 void Dfs2(int u,int chain)
 74 {
 75     num[u]=++stamp; top[u]=chain; vis[u]=true; int k=0;
 76     for (int i=head[u];i!=-1;i=edge[i].next)
 77         if (!vis[edge[i].to] && (siz[edge[i].to]>siz[k] || k==0)) k=edge[i].to;
 78     if (k==0) return;
 79     Dfs2(k,chain);
 80     for (int i=head[u];i!=-1;i=edge[i].next)
 81         if (!vis[edge[i].to] && edge[i].to!=k) Dfs2(edge[i].to,edge[i].to);
 82 }
 83
 84 inline int Lca(int u,int v)
 85 {
 86     while (true)
 87     {
 88         if (top[u]==top[v]) return dep[u]>dep[v]?v:u;
 89         if (dep[top[u]]>dep[top[v]]) u=father[top[u]]; else v=father[top[v]];
 90     }
 91 }
 92 //==================================================
 93
 94 inline void push_up(int o) {sum[o]=sum[o<<1]+sum[o<<1|1];}
 95 inline void Clr(int o) {clr[o]=1; sum[o]=0;}
 96 inline void push_down(int o) {if (clr[o]) Clr(o<<1),Clr(o<<1|1); clr[o]=0;}
 97 void Modify(int o,int l,int r,int p,int q)
 98 {
 99     if (l==p && r==q)
100     {
101         sum[o]=0;
102         clr[o]=1;
103         return;
104     }
105     push_down(o);
106     int mid=(l+r)>>1;
107     if (q<=mid) Modify(o<<1,l,mid,p,q);
108     if (p>=mid+1) Modify(o<<1|1,mid+1,r,p,q);
109     if (p<=mid && q>=mid+1) Modify(o<<1,l,mid,p,mid),Modify(o<<1|1,mid+1,r,mid+1,q);
110     push_up(o);
111 }
112 int Query(int o,int l,int r,int p,int q)
113 {
114     if (l==p && r==q) return sum[o];
115     push_down(o);
116     int mid=(l+r)>>1;
117     if (q<=mid) return Query(o<<1,l,mid,p,q);
118     if (p>=mid+1) return Query(o<<1|1,mid+1,r,p,q);
119     if (p<=mid && q>=mid+1) return Query(o<<1,l,mid,p,mid)+Query(o<<1|1,mid+1,r,mid+1,q);
120 }
121 void Build(int o,int l,int r)
122 {
123     if (l==r)
124     {
125         sum[o]=1;
126         return;
127     }
128     int mid=(l+r)>>1;
129     Build(o<<1,l,mid),Build(o<<1|1,mid+1,r);
130     push_up(o);
131 }
132
133 //=================================================
134 void Tree_Modify(int u,int v)
135 {
136     while (top[u]!=top[v])
137     {
138         Modify(1,1,scc,num[top[u]],num[u]);
139         u=father[top[u]];
140     }
141     Modify(1,1,scc,num[v],num[u]);
142 }
143 int Tree_Query(int u,int v)
144 {
145     int ret=0;
146
147     while (top[u]!=top[v])
148     {
149          ret+=Query(1,1,scc,num[top[u]],num[u]);
150         u=father[top[u]];
151     }
152     ret+=Query(1,1,scc,num[v],num[u]);
153     return ret;
154 }
155 //=================================================
156 void Tarjan(int u,int fa)
157 {
158     Low[u]=Dfn[u]=++Stamp; Stack[++apex]=u;
159     for(int i=head[u];i!=-1;i=edge[i].next)
160         if (edge[i].to!=fa)
161         {
162             int v=edge[i].to;
163             if(!Dfn[v])
164             {
165                 Tarjan(v,u);
166                 Low[u]=Min(Low[u],Low[v]);
167                 if(Low[v]>Dfn[u])
168                 {
169                     scc++;
170                     while(true) {int x=Stack[apex--]; Belong[x]=scc; if(x==v)break;}
171                 }
172             }
173             else Low[u]=Min(Low[u],Dfn[v]);
174         }
175     if(fa<0)
176     {
177         scc++;
178         while(true){int x=Stack[apex--]; Belong[x]=scc;    if(x==u)break;}
179     }
180 }
181 //=================================================
182
183 int main()
184 {
185     //freopen("c.in","r",stdin);
186     Get_Int(n),Get_Int(m);
187     for (int i=1;i<=m;i++)
188         Get_Int(u),Get_Int(v),Edge[mp(u,v)]=true,Edge[mp(v,u)]=true;
189
190     for (Q=1;;Q++)
191     {
192         Get_Int(Op[Q].type); if (Op[Q].type==-1) break;
193         Get_Int(Op[Q].u),Get_Int(Op[Q].v);
194         if (Op[Q].type==0) Edge[mp(Op[Q].u,Op[Q].v)]=false,Edge[mp(Op[Q].v,Op[Q].u)]=false;
195     }
196     Q--;
197     stamp=Stamp=cnt=0;
198     memset(head,-1,sizeof(head));
199     memset(vis,false,sizeof(vis));
200     memset(Low,0,sizeof(Low));
201     memset(Dfn,0,sizeof(Dfn));
202
203     Build_G();
204     Tarjan(1,-1);
205     Clear_G();
206     for (int i=1;i<=n;i++)
207         for (int j=head[i];j!=-1;j=edge[j].next)
208             if (Belong[i]!=Belong[edge[j].to])
209             {
210                 if (S.count(mp(Belong[i],Belong[edge[j].to]))==1) continue;
211                 S.insert(mp(Belong[i],Belong[edge[j].to]));
212                 S.insert(mp(Belong[edge[j].to],Belong[i]));
213                 V.pb(mp(Belong[i],Belong[edge[j].to]));
214                 V.pb(mp(Belong[edge[j].to],Belong[i]));
215             }
216
217
218     memset(head,-1,sizeof(head));cnt=0;
219     for (int i=0;i<V.size();i++) Add(V[i].fi,V[i].se);
220     father[1]=1;dep[1]=1;
221     memset(vis,false,sizeof(vis)),Dfs1(1);
222     memset(vis,false,sizeof(vis)),Dfs2(1,1);
223     Build(1,1,scc);
224     for (int i=Q;i>=1;i--)
225     {
226         int p=Belong[Op[i].u],q=Belong[Op[i].v];
227         if (Op[i].type==0)
228         {
229             if (p==q) continue;
230             int t=Lca(p,q);
231             if (t==p)
232             {
233                 int k=0;
234                 for (int j=head[t];j!=-1;j=edge[j].next)
235                     if (Lca(edge[j].to,q)==edge[j].to && father[t]!=edge[j].to) {k=edge[j].to; break;}
236
237                 Tree_Modify(q,k);
238                 continue;
239             }
240
241             if (t==q)
242             {
243                 int k=0;
244                 for (int j=head[t];j!=-1;j=edge[j].next)
245                     if (Lca(edge[j].to,p)==edge[j].to && father[t]!=edge[j].to) {k=edge[j].to; break;}
246                 Tree_Modify(p,k);
247                 continue;
248             }
249             int r,s;
250             for (int j=head[t];j!=-1;j=edge[j].next)
251                 if (Lca(edge[j].to,p)==edge[j].to && father[t]!=edge[j].to) {r=edge[j].to; break;}
252             for (int j=head[t];j!=-1;j=edge[j].next)
253                 if (Lca(edge[j].to,q)==edge[j].to && father[t]!=edge[j].to) {s=edge[j].to; break;}
254             Tree_Modify(p,r),Tree_Modify(q,s);
255         } else
256         if (Op[i].type==1)
257         {
258             if (p==q) {Ans[i]=0; continue;}
259             int t=Lca(p,q);
260             if (t==p)
261             {
262                 int k=0;
263                 for (int j=head[t];j!=-1;j=edge[j].next)
264                     if (Lca(edge[j].to,q)==edge[j].to && father[t]!=edge[j].to) {k=edge[j].to; break;}
265                 Ans[i]=Tree_Query(q,k);
266                 continue;
267             }
268             if (t==q)
269             {
270                 int k=0;
271                 for (int j=head[t];j!=-1;j=edge[j].next)
272                     if (Lca(edge[j].to,p)==edge[j].to && father[t]!=edge[j].to) {k=edge[j].to; break;}
273                 Ans[i]=Tree_Query(p,k);
274                 continue;
275             }
276
277             int r,s;
278             for (int j=head[t];j!=-1;j=edge[j].next)
279                 if (Lca(edge[j].to,p)==edge[j].to && father[t]!=edge[j].to) {r=edge[j].to; break;}
280             for (int j=head[t];j!=-1;j=edge[j].next)
281                 if (Lca(edge[j].to,q)==edge[j].to && father[t]!=edge[j].to) {s=edge[j].to; break;}
282             Ans[i]=Tree_Query(p,r)+Tree_Query(q,s);
283         }
284     }
285     for (int i=1;i<=Q;i++)
286         if (Op[i].type==1) Put_Int(Ans[i]);
287     return 0;
288 }
289
290     

傻逼树剖280+系列

时间: 2024-08-06 07:49:44

BZOJ 1969 树链剖分+Tarjan缩点的相关文章

bzoj 3083 树链剖分

首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集. /************************************************************** Problem: 3083 User: BLADEVIL Language: C++ Result: Accepted Time:6412 ms

spoj 375 AND bzoj 1036 树链剖分

树链剖分的入门题目,自己写了下感觉还是挺好写的,不过真的有点长... spoj 375 边有权值: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int INF = -999999999; 7 const int N = 10001; 8 int head[N]; 9 int sz[N]; 10 int depth[N]; 1

BZOJ 2243 树链剖分

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 题意:中文题目 思路:树链剖分.首先考虑求区间颜色段数的问题, 我们可以用线段树维护:区间左右端点(st,ed),区间颜色段数(val),懒惰标记(lazy:是否整个区间被染成同一种颜色),区间左右端点的颜色(lcolor,rcolor),然后在查询的时候如果当前区间的左子树的右端点的颜色等于右子树的左端点的颜色,那么查询答案要减一.由于树链剖分在查询时是有可能两端的分链一起向上爬

bzoj 1036 树链剖分+线段树 裸题

HYSBZ - 1036 题意:中文题 思路:树链剖分裸题,线段树写得比较搓,(在线段树上修改节点u的时候应该修改u映射到线段树后的节点序号,这里wa了半年,真的是半年) AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector

BZOJ 4326 树链剖分+二分+差分+记忆化

去年NOIP的时候我还不会树链剖分! 还是被UOJ 的数据卡了一组. 差分的思想还是很神啊! 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <ctime> 6 #include <cstdlib> 7 using namespace std; 8 const int Maxn=300100

bzoj 4196 树链剖分 模板

[Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2135  Solved: 1232[Submit][Status][Discuss] Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置.Debian/Ubu

BZOJ 1036 树链剖分模板题

BZOJ 1036 题意:一棵树,每个点有权值,三种操作:修改一个点的值:询问一条链上最大值:询问一条链上权值和. tags:模板题 // bzoj 1036 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define FF(i,a,b) for (int i=a;i<=b;i++) #define F(i,b,a)

BZOJ 2286 树链剖分+DFS序+虚树+树形DP

第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #define LL long long 6 using namespace std; 7 const LL Maxm=501000; 8 const LL Maxn=250100; 9 const LL Inf=1e60; 1

BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )

首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键边了, 因为形成了环, 环上任意2点有2条路径...下图, 加上蓝色的边, 红色x的边就变成了非关键边. 所以树链剖分维护一下...时间复杂度O(NlogN+MlogM+Qlog^2N), 可以AC. 翻了翻ZY的标解:“动态维护树+最近公共祖先查询”....复杂度是O(NlogN+M+QlogN)