HDU 5458 Stability
树链剖分,巨麻烦
题意
给一个图,可能有重边与自环。有一些操作:删去某条边,保证边一定存在;查询两点之间的桥数。保证任意时刻图至少是一棵树。
思路
老谭看一眼觉得是缩点,可能还要剖分,就丢给我。我敲完水题就开始了。。爆炸。。。
思路很清晰,两点之间的双联通分量一定对答案没有贡献,剩下的一条路贡献1。又最后保证联通,至少是树,所以思路很明显(有个NOI题,棘手的操作),先得到最后的图,倒着操作。
先读进图用map存,按操作删边,得到最后的图,建出链式前向星,跑一遍双联通分量缩点,这里我选择了重新建图,带着原图跑太容易写错了。对新图跑树链剖分,建线段树,每条路记成1。然后倒着操作来,加边[a,b]意味着有了新的双联通分量,相当于将[a,b]路径上的边权置为0。
竟然T了???我完美的Ologn的算法啊???调了两天,至今不知道为什么会T。。
看网上有说用并查集代替双联通缩点的,这样就是得到最后的图建链式前向星时,用并查集维护,如果两点已经联通,那么先不处理,把这个pair存起来。这样建出来的一定是树,跑树链剖分。在把刚才存起来的pair们的路径上的边置0,因为这些路相当于形成了双联通分量。然后过了。。。
我觉得缩点的复杂度要低很多啊,因为剖分时点就少了。。网上也有缩点过的%%%。并不知道我哪写丑了。
代码
AC
#include<bits\stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=30007;
const int MAXM=100007;
//OP
struct OP
{
int op, a, b;
}op[MAXM];
multiset<pair<int, int> >se;
multiset<pair<int, int> >sse;
//dsu
int fa[MAXN];
int getfa(int x)
{
return x==fa[x] ? x : fa[x]=getfa(fa[x]);
}
//Edge
struct Edge
{
int to, ne;
}e[MAXM<<2];
int head[MAXN], edgenum;
void addedge(int u, int v)
{
e[edgenum].to=v, e[edgenum].ne=head[u], head[u]=edgenum++;
e[edgenum].to=u, e[edgenum].ne=head[v], head[v]=edgenum++;
}
//
int Hson[MAXN], SonAmount[MAXN], Father[MAXN], Depth[MAXN];
int Dfsnum[MAXN], TopOfHeavyChain[MAXN];
int dfscount;
void dfs1(int n)
{
SonAmount[n]=1;
for(int i=head[n];~i;i=e[i].ne)
{
int to=e[i].to;
if(to==Father[n]/*||Depth[to]*/) continue;
Depth[to]=Depth[n]+1;
Father[to]=n;
dfs1(to);
SonAmount[n]+=SonAmount[to];
if(SonAmount[to]>SonAmount[Hson[n]]) Hson[n]=to;
}
return;
}
void dfs2(int n, int prev)
{
Dfsnum[n]=++dfscount;
TopOfHeavyChain[n]=prev;
if(!Hson[n]) return;
dfs2(Hson[n], prev);
for(int i=head[n];~i;i=e[i].ne)
{
int to=e[i].to;
if(to==Hson[n]||to==Father[n]) continue;
dfs2(to, to);
}
}
struct Stree
{
int num, lazy;
}stree[MAXN<<2];
inline void pushup(int rt)
{
stree[rt].num=stree[rt<<1].num+stree[rt<<1|1].num;
}
void build(int l, int r, int rt)
{
stree[rt].lazy=0;
if(l==r)
{
stree[rt].num=1;
return;
}
int mid=(l+r)>>1;
build(lson), build(rson);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt)
{
if(stree[rt].lazy) return;
if(L<=l&&r<=R)
{
stree[rt].lazy=1;
stree[rt].num=0;
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(L, R, lson);
if(mid<R) update(L, R, rson);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt)
{
if(stree[rt].lazy) return 0;
if(L<=l&&r<=R) return stree[rt].num;
int mid=(l+r)>>1;
int res=0;
if(L<=mid) res+=query(L, R, lson);
if(mid<R) res+=query(L, R, rson);
return res;
}
void solveup(int n, int l, int r)
{
int fl=TopOfHeavyChain[l], fr=TopOfHeavyChain[r];
while(fl!=fr)
{
if(Depth[fl]>Depth[fr])
{
update(Dfsnum[fl], Dfsnum[l], 1, n, 1);
l=Father[fl];fl=TopOfHeavyChain[l];
}
else
{
update(Dfsnum[fr], Dfsnum[r], 1, n, 1);
r=Father[fr];fr=TopOfHeavyChain[r];
}
}
if(l==r) return;
if(Depth[l]>Depth[r])
update(Dfsnum[Hson[r]], Dfsnum[l], 1, n, 1);
else update(Dfsnum[Hson[l]], Dfsnum[r], 1, n, 1);
}
int solvequ(int n, int l, int r)
{
int fl=TopOfHeavyChain[l], fr=TopOfHeavyChain[r];
int res=0;
while(fl!=fr)
{
if(Depth[fl]>Depth[fr])
{
res+=query(Dfsnum[fl], Dfsnum[l], 1, n, 1);
l=Father[fl];
fl=TopOfHeavyChain[l];
}
else
{
res+=query(Dfsnum[fr], Dfsnum[r], 1, n, 1);
r=Father[fr];
fr=TopOfHeavyChain[r];
}
}
if(l!=r)
{
if(Depth[l]>Depth[r])
{
res+=query(Dfsnum[Hson[r]], Dfsnum[l], 1, n, 1);
}
else
{
res+=query(Dfsnum[Hson[l]], Dfsnum[r], 1, n, 1);
}
}
return res;
}
void init(int n, int m)
{
se.clear();sse.clear();
for(int i=0;i<=n;i++) fa[i]=i;
M(head, -1);edgenum=0;
M(stree, 0);
M(Hson, 0);M(Depth, 0);
dfscount=0;Father[1]=1;Depth[1]=1;
}
int res[MAXM], rcnt;
int main()
{
int T;scanf("%d", &T);int cas=0;
while(T--)
{
int n, m, q;scanf("%d%d%d", &n, &m, &q);
init(n, m);
for(int i=1;i<=m;i++)
{
int a, b;scanf("%d%d", &a, &b);
if(a>b) swap(a, b);
se.insert(make_pair(a, b));
}
for(int i=1;i<=q;i++)
{
int o, a, b;scanf("%d%d%d", &o, &a, &b);
if(a>b) swap(a, b);
op[i].op=o, op[i].a=a, op[i].b=b;
if(o==1)
{
multiset<pair<int, int>>::iterator ite=se.find(make_pair(a, b));
se.erase(ite);
}
}
for(multiset<pair<int, int>>::iterator ite=se.begin();ite!=se.end();ite++)
{
int a=ite->first, b=ite->second;
int aa=getfa(a), bb=getfa(b);
if(aa!=bb)
{
fa[aa]=bb;
addedge(a, b);
}
else sse.insert(make_pair(a, b));
}
dfs1(1);dfs2(1, 1);build(1, n, 1);
for(multiset<pair<int, int>>::iterator ite=sse.begin();ite!=sse.end();ite++)
{
int a=ite->first, b=ite->second;
solveup(n, a, b);
}
rcnt=0;
for(int i=q;i>0;i--)
{
if(op[i].op==1)
{
solveup(n, op[i].a, op[i].b);
}
else
{
res[++rcnt]=(solvequ(n, op[i].a, op[i].b));
}
}
printf("Case #%d:\n", ++cas);
for(int i=rcnt;i>0;i--)
printf("%d\n", res[i]);
}
return 0;
}
缩点TLE
#include<bits\stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=30007;
const int MAXM=100007;
typedef long long LL;
//Operator
struct OP
{
int op;
int a, b;
int res;
OP() { op=a=b=0; }
void read() { scanf("%d%d%d", &op, &a, &b); }
}op[MAXM];
//Edge,Targan
struct Edge
{
int to, ne;
int fl;
}e[MAXM<<2];
int head[MAXN], edgenum;
vector<int> G[MAXN];
void addedge(int u, int v)
{
e[edgenum].to=v, e[edgenum].ne=head[u], e[edgenum].fl=0, head[u]=edgenum++;
e[edgenum].to=u, e[edgenum].ne=head[v], e[edgenum].fl=0, head[v]=edgenum++;
}
struct Targan
{
int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
stack<int> S;
void init()
{
while(!S.empty()) S.pop();
}
void dfs(int u, int fa)
{
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=head[u];~i;i=e[i].ne)
{
int v=e[i].to;
if(v==fa||e[i].fl) continue;
if(!pre[v])
{
dfs(v, u);
lowlink[u]=min(lowlink[u], lowlink[v]);
}
else
{
lowlink[u]=min(lowlink[u], pre[v]);
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
while(1)
{
int x=S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u) break;
}
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
M(sccno, 0);M(pre, 0);M(lowlink, 0);
for(int i=1;i<=n;i++)
{
if(!pre[i]) dfs(i, -1);
}
}
}targan;
int Hson[MAXN], SonAmount[MAXN], Father[MAXN], Depth[MAXN];
int Dfsnum[MAXN], TopOfHeavyChain[MAXN];
int dfscount;
void dfs1(int n)
{
SonAmount[n]=1;
for(int i=0;i<G[n].size();i++)
{
int to=G[n][i];
if(to==Father[n]) continue;
Depth[to]=Depth[n]+1;
Father[to]=n;
dfs1(to);
SonAmount[n]+=SonAmount[to];
if(SonAmount[to]>SonAmount[Hson[n]]) Hson[n]=to;
}
return;
}
void dfs2(int n, int prev)
{
Dfsnum[n]=++dfscount;
TopOfHeavyChain[n]=prev;
if(!Hson[n]) return;
dfs2(Hson[n], prev);
for(int i=0;i<G[n].size();i++)
{
int to=G[n][i];
if(to==Hson[n]||to==Father[n]) continue;
dfs2(to, to);
}
}
struct Stree
{
int lazy;int num;
Stree() { lazy=0;num=0; }
}stree[MAXN<<2];
inline void pushup(int rt)
{
stree[rt].num=stree[rt<<1].num+stree[rt<<1|1].num;
}
void build(int l, int r, int rt)
{
stree[rt].lazy=0;
if(l==r) { stree[rt].num=1;return; }
int mid=(l+r)>>1;
build(lson), build(rson);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt)
{
if(stree[rt].lazy) return;
if(L<=l&&r<=R)
{
stree[rt].lazy=1;
stree[rt].num=0;
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(L, R, lson);
if(mid<R) update(L, R, rson);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt)
{
if(stree[rt].lazy) return 0;
if(L<=l&&r<=R) return stree[rt].num;
int mid=(l+r)>>1;
int res=0;
if(L<=mid) res+=query(L, R, lson);
if(mid<R) res+=query(L, R, rson);
return res;
}
void solveup(int n, int l, int r)
{
int fl=TopOfHeavyChain[l], fr=TopOfHeavyChain[r];
while(fl!=fr)
{
if(Depth[fl]>Depth[fr])
{
update(Dfsnum[fl], Dfsnum[l], 1, n, 1);
l=Father[fl];fl=TopOfHeavyChain[l];
}
else
{
update(Dfsnum[fr], Dfsnum[r], 1, n, 1);
r=Father[fr];fr=TopOfHeavyChain[r];
}
}
if(l==r) return;
if(Depth[l]>Depth[r])
update(Dfsnum[Hson[r]], Dfsnum[l], 1, n, 1);
else update(Dfsnum[Hson[l]], Dfsnum[r], 1, n, 1);
}
int solvequ(int n, int l, int r)
{
int fl=TopOfHeavyChain[l], fr=TopOfHeavyChain[r];
int res=0;
while(fl!=fr)
{
if(Depth[fl]>Depth[fr])
{
res+=query(Dfsnum[fl], Dfsnum[l], 1, n, 1);
l=Father[fl];
fl=TopOfHeavyChain[l];
}
else
{
res+=query(Dfsnum[fr], Dfsnum[r], 1, n, 1);
r=Father[fr];
fr=TopOfHeavyChain[r];
}
}
if(l!=r)
{
if(Depth[l]>Depth[r])
{
res+=query(Dfsnum[Hson[r]], Dfsnum[l], 1, n, 1);
}
else
{
res+=query(Dfsnum[Hson[l]], Dfsnum[r], 1, n, 1);
}
}
return res;
}
int main()
{
int T;scanf("%d", &T);int cas=0;
while(T--)
{
printf("Case #%d:\n", ++cas);
M(head, -1);edgenum=0;
int n, m, q;scanf("%d%d%d", &n, &m, &q);
for(int i=1;i<=m;i++)
{
int u, v;scanf("%d%d", &u, &v);
addedge(u, v);
}
for(int i=1;i<=q;i++)
{
int o, a, b;scanf("%d%d%d", &o, &a, &b);
if(a>b) swap(a, b);
op[i].op=o, op[i].a=a, op[i].b=b;
if(o==1)
{
for(int j=head[a];~j;j=e[j].ne)
{
if(e[j].to==b)
{
e[j].fl=1, e[j^1].fl=1;
break;
}
}
}
}
targan.init();
targan.find_scc(n);
for(int i=1;i<=n;i++) G[i].clear();
for(int i=1;i<=n;i++)
{
int u=0, v=0;u=targan.sccno[i];
for(int j=head[i];~j;j=e[j].ne)
{
if(e[j].fl) continue;
v=targan.sccno[e[j].to];
if(u>targan.scc_cnt||v>targan.scc_cnt) assert("dsf");
G[u].push_back(v);
G[v].push_back(u);
}
}
n=targan.scc_cnt;
for(int i=1;i<=n;i++)
{
sort(G[i].begin(), G[i].end());
G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
}
M(Hson, 0);M(Depth, 0);
Father[1]=1;Depth[1]=1;dfscount=0;
dfs1(1), dfs2(1, 1);build(1, n, 1);
for(int i=q;i>0;i--)
{
if(op[i].op==1)
{
solveup(n, targan.sccno[op[i].a], targan.sccno[op[i].b]);
}
else
{
op[i].res=solvequ(n, targan.sccno[op[i].a], targan.sccno[op[i].b]);
}
}
for(int i=1;i<=q;i++)
{
if(op[i].op==2) printf("%d\n", op[i].res);
}
}
//system("pause");
return 0;
}