Created
October 20, 2012 16:43
-
-
Save zxytim/3923939 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************** | |
Problem: 1969 | |
User: zxytim | |
Language: C++ | |
Result: Accepted | |
Time:654 ms | |
Memory:7568 kb | |
****************************************************************/ | |
/* | |
* $File: lane.cpp | |
* $Date: Fri Jun 04 07:14:39 2010 +0800 | |
* $Prob: AHOI2005 lane | |
* $Solution: | |
* 1. off-line algorithm, deal queries and modification in reverse order | |
* 2. LCA -- Sparse Table Algorithm | |
* 3. Tree structured arrary -- maintain distance from one node to root | |
* 4. Disjoint set -- merge adjacent not-cut edge in the tree | |
*/ | |
#include <cstdio> | |
#include <cstdlib> | |
#include <cstring> | |
#include <algorithm> | |
#define MAXN 30010 | |
#define MAXQ 40010 | |
#define MAXM 100010 * 2 | |
#define Lowbit(x) ((x) & (-(x))) | |
#define OP(x) ((((x) - 1) ^ 1) + 1) | |
using namespace std; | |
class Edge | |
{ | |
public: | |
int a, b; | |
}; | |
class Query | |
{ | |
public: | |
int c, a, b, data; | |
// when c == 0, data stands for edge id which connect a and b | |
// when c == 1, data stands for answer of this query | |
}; | |
Query query[MAXQ + 1]; | |
Edge e[MAXM + 1]; | |
int Count = 0; | |
int begin[MAXN + 1], next[MAXM + 1], end[MAXM + 1]; | |
void AddEdge(int a, int b) | |
{ | |
Count ++; | |
next[Count] = begin[a]; | |
begin[a] = Count; | |
end[Count] = b; | |
} | |
int n, m, Q; | |
void Init() | |
{ | |
scanf("%d%d", &n, &m); | |
int a, b, c; | |
for (int i = 1; i <= m; i ++) | |
{ | |
scanf("%d%d", &a, &b); | |
if (a > b) | |
swap(a, b); | |
e[i].a = a, e[i].b = b; | |
} | |
while (scanf("%d%d%d", &c, &a, &b) == 3) | |
{ | |
Q ++; | |
if (a > b) | |
swap(a, b); | |
query[Q].c = c, query[Q].a = a, query[Q].b = b; | |
} | |
} | |
bool cmpEdge(const Edge &a, const Edge &b) | |
{ | |
if (a.a == b.a) | |
return a.b < b.b; | |
return a.a < b.a; | |
} | |
int GetEdgeID(int a, int b) | |
{ | |
Edge et; | |
et.a = a, et.b = b; | |
int l = 1, r = m; | |
while (l < r) | |
{ | |
int mid = (l + r) >> 1; | |
if (cmpEdge(e[mid], et)) | |
l = mid + 1; | |
else | |
r = mid; | |
} | |
return l; | |
} | |
bool hashedge[MAXM + 1]; | |
void AddInitEdge() | |
{ | |
sort(e + 1, e + 1 + m, cmpEdge); | |
for (int i = 1; i <= Q; i ++) | |
if (query[i].c == 0) | |
{ | |
query[i].data = GetEdgeID(query[i].a, query[i].b); | |
hashedge[query[i].data] = true; | |
} | |
for (int i = 1; i <= m; i ++) | |
if (!hashedge[i]) | |
{ | |
AddEdge(e[i].a, e[i].b); | |
AddEdge(e[i].b, e[i].a); | |
} | |
} | |
int Log[MAXN * 2 + 1]; | |
int f[MAXN * 2 + 1][19]; | |
int L[MAXN + 1], R[MAXN + 1]; | |
int Father[MAXN + 1]; | |
int dep[MAXN + 1]; | |
bool hash[MAXN + 1]; | |
int N = 0; | |
bool intree[MAXM + 1]; | |
void dfs(int x) | |
{ | |
hash[x] = true; | |
N ++; | |
f[N][0] = x; | |
L[x] = N; | |
for (int now = begin[x]; now; now = next[now]) | |
if (!hash[end[now]]) | |
{ | |
intree[now] = intree[OP(now)] = true; | |
Father[end[now]] = x; | |
dep[end[now]] = dep[x] + 1; | |
dfs(end[now]); | |
f[++N][0] = x; | |
} | |
R[x] = N; | |
} | |
int c[MAXN * 2 + 1]; | |
void Add(int p, int v) | |
{ | |
while (p <= N) | |
c[p] += v, p += Lowbit(p); | |
} | |
int Sum(int p) | |
{ | |
int ret = 0; | |
while (p) | |
ret += c[p], p -= Lowbit(p); | |
return ret; | |
} | |
int LCA(int a, int b) | |
{ | |
a = L[a], b = L[b]; | |
if (a > b) | |
swap(a, b); | |
int k = Log[b - a + 1]; | |
int id1 = f[a][k], id2 = f[b - (1 << k) + 1][k]; | |
if (dep[id1] < dep[id2]) | |
return id1; | |
return id2; | |
} | |
int father[MAXN + 1]; | |
int Getfather(int x) | |
{ | |
if (x == father[x]) | |
return x; | |
return father[x] = Getfather(father[x]); | |
} | |
void CoverRoute(int a, int fa) | |
{ | |
while (dep[a] > dep[fa]) | |
{ | |
a = Getfather(a); | |
if (dep[a] > dep[fa]) | |
{ | |
Add(L[a], -1); | |
Add(R[a] + 1, 1); | |
father[a] = Father[a]; | |
} | |
} | |
} | |
void Cover(int a, int b) | |
{ | |
int fa = LCA(a, b); | |
CoverRoute(a, fa); | |
CoverRoute(b, fa); | |
} | |
void Init_LCA_Dist_DisjointSet_Tree() | |
{ | |
dfs(1); | |
// Init LCA | |
for (int i = 0; (1 << i) <= N; i ++) | |
for (int j = (1 << i); j < (1 << (i + 1)) && j <= N; j ++) | |
Log[j] = i; | |
int t; | |
for (int j = 1; (1 << j) <= N; j ++) | |
for (int i = 1; i <= N; i ++) | |
{ | |
f[i][j] = f[i][j - 1]; | |
t = i + (1 << (j - 1)); | |
if (t <= N) | |
{ | |
if (dep[f[t][j - 1]] < dep[f[i][j]]) | |
f[i][j] = f[t][j - 1]; | |
} | |
} | |
// Init Dist | |
for (int i = 1; i <= n; i ++) | |
{ | |
Add(L[i], 1); | |
Add(R[i] + 1, -1); | |
} | |
// Init disjoint set | |
for (int i = 1; i <= n; i ++) | |
father[i] = i; | |
// Init Tree | |
for (int i = 1; i <= n; i ++) | |
for (int now = begin[i]; now; now = next[now]) | |
if (!intree[now]) | |
{ | |
intree[now] = intree[OP(now)] = true; | |
Cover(i, end[now]); | |
} | |
} | |
int Ask(int a, int b) | |
{ | |
int fa = LCA(a, b); | |
return Sum(L[a]) + Sum(L[b]) - Sum(L[fa]) * 2; | |
} | |
void DealQuery() | |
{ | |
for (int i = Q; i >= 1; i --) | |
if (query[i].c == 0) | |
Cover(query[i].a, query[i].b); | |
else | |
query[i].data = Ask(query[i].a, query[i].b); | |
} | |
void Solve() | |
{ | |
AddInitEdge(); | |
Init_LCA_Dist_DisjointSet_Tree(); | |
DealQuery(); | |
} | |
void Print() | |
{ | |
for (int i = 1; i <= Q; i ++) | |
if (query[i].c == 1) | |
printf("%d\n", query[i].data); | |
} | |
int main() | |
{ | |
Init(); | |
Solve(); | |
Print(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment