C - ベリージャム
2Nジャーに、即ち[1,2n]を構成する、に立っ[N、N + 1]中間体のため、赤色および残りの缶ことは、この点を左及び右の連続期間の継続期間を食べあって質問が意図されています青色の同数。少なくとも瓶で食べます。
解決策:アップデートで見つかっ反対数、内側右およびクエリ地図上に赤1青と-1、その後、左のプレフィックスにマップを入れて、内部に挿入し、接尾辞。それは同じ値であるためできるだけ食べて、現存するマップは右端の接頭辞でなければならないことに注意してください。
注意!0とに接頭辞と接尾辞を追加するには!
しかし、サイトが見られ、サンプル検証するだけでなく、少し改善する能力を行うことができます。
4
1 1 1 1 1 2 1 2
PPは、真の良心であってもよいです。
int n;
int a[2000005];
int prefix[2000005];
int suffix[2000005];
map<int, int> M;
void test_case() {
scanf("%d", &n);
M.clear();
for(int i = 0; i <= 2 * n + 1; ++i) {
prefix[i] = 0;
suffix[i] = 0;
}
for(int i = 1; i <= 2 * n; ++i) {
scanf("%d", &a[i]);
if(a[i] == 2)
a[i] = -1;
}
for(int i = 1; i <= 2 * n; ++i)
prefix[i] = prefix[i - 1] + a[i];
for(int i = 2 * n; i >= 1; --i)
suffix[i] = suffix[i + 1] + a[i];
int ans = 0;
for(int i = 0; i <= n; ++i)
M[prefix[i]] = i;
for(int i = 2 * n + 1; i >= n + 1; --i) {
int t = -suffix[i];
if(M.count(t)) {
ans = max(ans, M[t] + 2 * n + 1 - i);
//cout << "i=" << M[t] << " j=" << 2 * n + 1 - i << endl;
}
}
printf("%d\n", 2 * n - ans);
}
D - セグメントツリー
質問が意図される:2N桁に、それぞれ数字[1、n]は、正確に2回出現する、初めて[i]はLと呼ばれる、第二は、[i]はRと呼ばれています。代表のライン断面の任意の2点間であってもエッジが、私たちも木を依頼されていません。
溶液:バランスのとれたツリーソートR、Lが、それはバランスのとれたツリー内に挿入された遭遇は、その後、彼らは、現在のノードも全体のエッジのすべてのR <r個の点を除去しました。エッジがNまたは環(実際にはN側に接続された環を有するであろう)よりも小さくない場合でも、それがツリーにすることはできません。もちろん、いなくても、N-1の側面は、ツリーではないであろう。
これは、ヒープで簡単に発注し、高速またはバランスの取れたツリーを思わについても繰り返し、小さいが一定の複数のログを取り出しました。
struct DisjointSetUnion {
static const int MAXN = 1000005;
int n, fa[MAXN + 5], rnk[MAXN + 5];
void Init(int _n) {
n = _n;
for(int i = 1; i <= n; i++) {
fa[i] = i;
rnk[i] = 1;
}
}
int Find(int u) {
int r = fa[u];
while(fa[r] != r)
r = fa[r];
int t;
while(fa[u] != r) {
t = fa[u];
fa[u] = r;
u = t;
}
return r;
}
bool Merge(int u, int v) {
u = Find(u), v = Find(v);
if(u == v)
return false;
else {
if(rnk[u] < rnk[v])
swap(u, v);
fa[v] = u;
rnk[u] += rnk[v];
return true;
}
}
} dsu;
int n;
int l[1000005], r[1000005];
int a[1000005];
set<pii> PQ;
void test_case() {
scanf("%d", &n);
PQ.clear();
dsu.Init(2 * n);
a[0] = a[2 * n + 1] = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &l[i], &r[i]);
a[l[i]] = i;
a[r[i]] = -i;
}
int cntedge = 0;
for(int i = 1; i <= 2 * n; ++i) {
if(a[i] > 0) {
int id = a[i];
//cout << "id=" << id << endl;
for(auto &e : PQ) {
if(r[id] < e.first)
break;
if(dsu.Merge(e.second, id)) {
//printf("%d - %d\n", e.second, id);
++cntedge;
if(cntedge >= n) {
puts("NO");
return;
}
} else {
//printf("%d - %d but \n", e.second, id);
puts("NO");
return;
}
}
PQ.insert({r[id], id});
} else {
PQ.erase(PQ.begin());
//int id = -a[i];
}
}
if(cntedge == n - 1)
puts("YES");
else
puts("NO");
}
E - 問題のテストD
問題の意味:配列を構築するために、ツリー、木がDの問題を復元することができるようにということ。
解決策:検索が広いように見えるを開始しますが、全体の検索でなく、深い検索のようなビット。オーダーの隣接点を通過すると、FIFOである一方で、すべての隣人やポップ業界のポイントの右にスタック全体の父を除いて、それにポイントを通過した後、それはそう、背面側に接続することはありません兄弟間の関係が含まれています。注意!リーフノードの次数<= 1ポイント!異常な状況に注意してください。
int root;
vector<int> G[500005];
void dfs1(int u, int p) {
if(G[u].size() <= 1) {
root = u;
return;
}
for(auto &v : G[u]) {
if(v == p)
continue;
dfs1(v, u);
if(root)
return;
}
}
int ans[1000005], cnt;
int pa[500005];
stack<int> st;
void dfs(int u) {
for(auto &v : G[u]) {
if(v == pa[u])
continue;
ans[++cnt] = v;
pa[v] = u;
st.push(v);
}
}
int l[500005], r[500005];
void test_case() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n - 1; ++i) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1, -1);
ans[++cnt] = root;
st.push(root);
pa[root] = -1;
while(st.size()) {
int u = st.top();
st.pop();
dfs(u);
ans[++cnt] = u;
}
for(int i = 1; i <= cnt; ++i) {
int t = ans[i];
if(l[t] == 0)
l[t] = i;
else
r[t] = i;
//printf("%d%c", ans[i], " \n"[i == cnt]);
}
for(int i = 1; i <= n; ++i)
printf("%d %d\n", l[i], r[i]);
}
しかし、これは木、ネストされたシーケンスDFN順序それのようではありません、慎重にと思いますか?唯一の父は、ネストされたサブツリー、およびサブツリーを停止したが、断面は、そのDFSの変化に応じて自然です。次回は恐れることはありません。