フェイス質問
2049:[Sdoi2008]洞窟の洞窟の調査
時間制限:10秒メモリ制限:259メガバイト
提出:12030解決:6024
説明
洞窟の調査に熱心シャイン。ある日、彼はマップに従ってJSZXグループ領域としてマークされている洞窟に来ました。予備調査の後、我々はNによってこの領域の洞窟を照らす見出した(それぞれnまで番号1)と、複数のチャネルの組成、及び各チャネルは、ちょうど二つの洞窟に接続されています。2つの洞窟がので、2つの洞窟通信することを、特定の順序で一緒に一つまたは複数のチャネルによって接続することができる場合、これらのチャネルは、二つの洞窟間のパスと呼ばれる配列で一緒に接続しました。洞窟は破壊されない非常に強い缶であるが、チャネルが非常に安定していない、しばしば外部からの影響との変化、例えば、監視結果に応じて、関連する器具、123と127の洞窟の間に時々洞窟通路、時にはこのチャネルこれは、理由は奇妙なのいくつかの種類の破壊されます。、uは間V洞窟に監視し、洞窟のチャンネルがあった場合には、端末上で検出された場合は、コマンド接続UVを表示します。Huihuiは、リアルタイムの監視装置は、チャネルAの状態が手元の端末輝きに表示されるたびに変更することができます持っていますuは破壊され、V洞窟や洞窟の間のチャネル、ディスプレイ命令は、端末上の長い骨の折れる手動投影した後、紫外線を破壊し、輝きは奇妙な現象を発見:任意の二つの洞窟の間にチャンネルを変えるどんなに、随時アップ唯一のパス。このように、輝きが、これが原因といくつかの基本的なルールの支配によるものであると信じています。このように、ターミナル前輝きの昼と夜のスティックより、自然チャンネルの法律を変更することで、この状況を調査しようとしています。しかし、彼はグランド端子(ターミナルも十分に強い破壊しない)にドロップを入れて......で1日、輝きが紙微積分の山に墜落し、あなたに向いて言った:「あなたは男を入れてそれについて書くためのプログラム。」常に、ターミナルの問題を通じて指示クエリ紫外線を輝きたいモニタケースの洞窟を尋ねると、uはV洞窟が到達可能です。今、あなたは彼がすべてのお問い合わせにお答えするためのプログラムを記述する必要があります。最初の命令ディスプレイの前に知られている、JSZXにはチャネルが存在しない洞窟存在しています。
入力
最初の2つの正の整数nおよび行動mは、それぞれ、洞窟や命令の端子数に現れ数を表します。次の行mは、端末に表示される指示のシーケンスを示します。各行の先頭文字列sのタイプを示すコマンドである(「接続」、「クエリ」を「破壊」または、大文字と小文字を区別)、2つの整数uおよびv(1≤u、v≤nおよびu≠vが存在します)番号2洞窟を示します。
出力
出力は「はい」、そうでない場合は「いいえ」である:uは相互に接続されているかどうかv各出力洞窟や洞窟のためのクエリコマンド。(引用符なし)
サンプル入力
サンプル入力cave.in. 1
200である。5
クエリ123 127
接続123 127
クエリ123 127
127 123破壊
クエリ123 127
2 cave.inサンプル入力を
3. 5
に接続します。1 2
接続。3. 1
クエリ2.3
破壊する。3. 1
クエリ2 3
サンプル出力
Cave.outサンプル出力。1つの
なし
はい
なしの
サンプル出力2 cave.out
はい
ません
ヒント
データ記述データ満足の10%n≤1000、データを満たすのm≤2000020%n≤2000、データ満たすn≤3000のm≤4000030%、データを満たすのm≤6000040%n≤4000、m≤80000データ満たすn≤5000の50%、データ満たすn≤6000のm≤10000060%、データ満たすn≤7000のm≤12000070%、データ満たすn≤8000のm≤14000080%、90%m≤160000データ会うn≤10000へのデータのn≤9000、m≤180000100%を満たしている、すべての命令が破壊破壊することを保証m≤200000問題で比較的大きく、このチャンネルの入力と出力に存在し、それがC \ C ++推奨されており、プレイヤーはscanf関数を使用します回避タイムアウトに順にprintfの行為I \ O操作
分析
そこ(ここでは、コマンドの各行は、時間の単位で指定された)一辺の時間が実際の時間の連続期間であるので、我々はオフラインの問題を置くことができます。
そして、我々は私達の木の線分の両側にノードのセットを保存することは難しいことではありません、全体の状態を保存するために、ツリーラインを使用することができ、このノードは、すべての子ノードは、このエッジを含んで表しています。
すべての側面のコレクションの全体のプロセスを通過するリーフノードへのルートノードから任意の葉ノードの場合、我々は、現在のマップで構成されているので
、すべての問い合わせは、ルートノードから開始している場合により、その効率は、我々が直接オンラインを使用し、低すぎます効率の問題を解決する方法を移動ツリーのセクション。
セグメントツリーの移動を達成するために、検査およびセットのプロパティを介して抜き出さ
ACコード
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10100;
const int MAXM = 200100;
typedef pair<int, int> pii;
struct UFS {
int f[MAXN];
stack<pii> s;
int finds(int x) {
while (x ^ f[x])
x = f[x];
return x;
}
void unite(int x, int y) {
x = finds(x);
y = finds(y);
if (x != y) {
s.push({x, f[x]});
f[x] = y;
}
}
void init(int b, int e) { // 初始化函数,范围为 [b, e)
for (int i = b; i < e; i++)
f[i] = i;
}
void undo() {
f[s.top().first] = s.top().second;
s.pop();
}
};
struct SegTree {
vector<pii> data[MAXM << 2];
static inline int lson(int k) { return k << 1; }
static inline int rson(int k) { return (k << 1) | 1; }
static inline int fat(int l, int r) { return (l + r) >> 1; }
// add 函数对应于正常的线段树的 insert,但是稍微有些不同
void add(int k, int l, int r, int x, int y, const pii &value) {
if (l == x && r == y) {
data[k].push_back(value);
return;
}
int mid = fat(l, r);
if (y <= mid) {
add(lson(k), l, mid, x, y, value);
} else if (x > mid) {
add(rson(k), mid + 1, r, x, y, value);
} else {
add(lson(k), l, mid, x, mid, value);
add(rson(k), mid + 1, r, mid + 1, y, value);
}
}
};
UFS ufs;
SegTree segTree;
vector<pair<pii, int> > que;
int tar;
// 通过 dfs 的方式在线段树上移动
bool dfs(int k, int l, int r) {
// 当完成一次询问之后,需要跳出当前的叶子,即回溯。通过 goto 来使得回溯的过程会自动进入正确的叶子节点
rejudge:
int target = que[tar].second;
if (target == r && l == r) {
if (ufs.finds(que[tar].first.first) == ufs.finds(que[tar].first.second))
cout << "Yes" << endl;
else
cout << "No" << endl;
tar++;
return tar == que.size();// true 表示所有的询问已经结束,退出 dfs
}
int mid = SegTree::fat(l, r);
if (target <= mid) {
// for (auto &item: segTree.data[SegTree::lson(k)])
// ufs.unite(item.first, item.second);
for (int i = 0; i < segTree.data[SegTree::lson(k)].size(); ++i)
ufs.unite(segTree.data[SegTree::lson(k)][i].first, segTree.data[SegTree::lson(k)][i].second);
if (dfs(SegTree::lson(k), l, mid))
return true;
// for (auto &item: segTree.data[SegTree::lson(k)])
for (int i = 0; i < segTree.data[SegTree::lson(k)].size(); ++i)
ufs.undo();
if (que[tar].second > r)
return false;
goto rejudge;
} else {
// for (auto &item: segTree.data[SegTree::rson(k)])
// ufs.unite(item.first, item.second);
for (int i = 0; i < segTree.data[SegTree::rson(k)].size(); ++i)
ufs.unite(segTree.data[SegTree::rson(k)][i].first, segTree.data[SegTree::rson(k)][i].second);
if (dfs(SegTree::rson(k), mid + 1, r))
return true;
// for (auto &item: segTree.data[SegTree::rson(k)])
for (int i = 0; i < segTree.data[SegTree::rson(k)].size(); ++i)
ufs.undo();
if (que[tar].second > r)
return false;
goto rejudge;
}
}
void solve() {
int n, m;
cin >> n >> m;
map<pii, int> mp;
for (int i = 0; i < m; ++i) {
string s;
int u, v;
cin >> s >> u >> v;
if (u > v) swap(u, v);
switch (s[0]) {
case 'Q':
// que.push_back({{u, v}, i + 1});
que.push_back(make_pair(make_pair(u, v), i + 1));
break;
case 'C':
// mp.insert({{u, v}, i + 1});
mp.insert(make_pair(make_pair(u, v), i + 1));
break;
case 'D': {
// auto iter = mp.find({u, v});
map<pii, int>::iterator iter = mp.find(make_pair(u, v));
// segTree.add(1, 1, m, iter->second, i, {u, v});
segTree.add(1, 1, m, iter->second, i, make_pair(u, v));
mp.erase(iter);
break;
}
}
}
map<pii, int>::iterator iter = mp.begin();
while (iter != mp.end()) {
segTree.add(1, 1, m, iter->second, m, iter->first);
iter++;
}
ufs.init(0, n + 1);
tar = 0;
// for (auto &item: segTree.data[1])
for (int i = 0; i < segTree.data[1].size(); ++i)
ufs.unite(segTree.data[1][i].first, segTree.data[1][i].second);
// ufs.unite(item.first, item.second);
dfs(1, 1, m);
return;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// cin.tie(nullptr);
// cout.tie(nullptr);
#ifdef ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long long test_index_for_debug = 1;
char acm_local_for_debug;
while (cin >> acm_local_for_debug) {
if (acm_local_for_debug == '$') exit(0);
cin.putback(acm_local_for_debug);
if (test_index_for_debug > 20) {
throw runtime_error("Check the stdin!!!");
}
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
}
#else
solve();
#endif
return 0;
}