結果
| 問題 | No.1698 Face to Face |
| コンテスト | |
| ユーザー |
eSeF
|
| 提出日時 | 2021-06-14 00:59:29 |
| 言語 | C# (.NET 8.0.404) |
| 結果 |
AC
|
| 実行時間 | 966 ms / 5,000 ms |
| コード長 | 11,337 bytes |
| コンパイル時間 | 16,348 ms |
| コンパイル使用メモリ | 166,632 KB |
| 実行使用メモリ | 243,272 KB |
| 最終ジャッジ日時 | 2024-07-19 09:43:35 |
| 合計ジャッジ時間 | 40,341 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 45 |
コンパイルメッセージ
復元対象のプロジェクトを決定しています... /home/judge/data/code/main.csproj を復元しました (94 ms)。 MSBuild のバージョン 17.9.6+a4ecab324 (.NET) main -> /home/judge/data/code/bin/Release/net8.0/main.dll main -> /home/judge/data/code/bin/Release/net8.0/publish/
ソースコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Numerics;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using static System.Math;
using static System.Array;
using static AtCoder.Cout;
using static AtCoder.Tool;
namespace AtCoder
{
class AC
{
const int MOD = 1000000007;
//const int MOD = 998244353;
const int INF = int.MaxValue / 2;
const long SINF = long.MaxValue / 3;
static readonly int[] dI = { 0, 1, 0, -1, 1, -1, -1, 1 };
static readonly int[] dJ = { 1, 0, -1, 0, 1, 1, -1, -1 };
static void Main(string[] args)
{
var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }; Console.SetOut(sw);
/*var th = new Thread(Run, 1 << 26);
th.Start();
th.Join();*/
Run();
Console.Out.Flush();
}
static void Run()
{
int Testcase = 1;
//Testcase = Cin.Int;
for (var _ = 0; _ < Testcase; _++) Solve();
}
static void Solve()
{
int N = Cin.Int;
var A = Cin.ReadSplitInt;
var B = Cin.ReadSplitInt;
var Z = Cin.ReadSplitInt;
var ida = new int[N];
var idb = new int[N];
for (var i = 0; i < N; i++)
{
A[i]--; B[i]--; Z[i]--;
ida[A[i]] = idb[B[i]] = i;
}
var f = new int[N];//ペア i,Z_i が実現可能な最小の k
var pt = new int[N];// k=f[i] において、ペアを配置できる代表点
var l = new int[N];
var r = new int[N];
for (var i = 0; i < N; i++)
{
l[i] = -1;
r[i] = N;
pt[i] = -1;
}
var mids = new Queue<int>[N];
for (var i = 0; i < N; i++) mids[i] = new Queue<int>();
for (var _ = 0; _ < 18; _++)
{
for (var i = 0; i < N; i++) mids[(l[i] + r[i]) / 2].Enqueue(i);
var ufa = new ExtUnionFind(N);
var ufb = new ExtUnionFind(N);
for (var k = 0; k < N; k++)
{
int ia = ida[k];
int ib = idb[k];
if (ia - 1 >= 0 && A[ia - 1] <= k) ufa.Unite(ia, ia - 1);
if (ia + 1 < N && A[ia + 1] <= k) ufa.Unite(ia, ia + 1);
if (ib - 1 >= 0 && B[ib - 1] <= k) ufb.Unite(ib, ib - 1);
if (ib + 1 < N && B[ib + 1] <= k) ufb.Unite(ib, ib + 1);
while(mids[k].Any())
{
var q = mids[k].Dequeue();
int la = ufa.Lef(ida[q]), ra = ufa.Rig(ida[q]);
int lb = ufb.Lef(idb[Z[q]]), rb = ufb.Rig(idb[Z[q]]);
if (ra < lb || rb < la)
{
l[q] = k;
}
else
{
r[q] = k;
pt[q] = Max(la, lb);
}
}
}
}
for (var i = 0; i < N; i++) f[i] = r[i];
//OutL($"result:");
//Out_Sep(f);
//Out_Sep(pt);
//OutL($"=========");
var uf = new ExtUnionFind2(N);
var pos = new List<int>[N];
for (var i = 0; i < N; i++) pos[i] = new List<int>();
for (var i = 0; i < N; i++) pos[f[i]].Add(i);
var act = new int[N];
for (var k = 0; k < N; k++)
{
act[ida[k]]++;
if (act[ida[k]] == 2)
{
int id = ida[k];
if (id > 0 && act[id - 1] == 2) uf.Unite(id, id - 1);
if (id + 1 < N && act[id + 1] == 2) uf.Unite(id, id + 1);
}
act[idb[k]]++;
if (act[idb[k]] == 2)
{
int id = idb[k];
if (id > 0 && act[id - 1] == 2) uf.Unite(id, id - 1);
if (id + 1 < N && act[id + 1] == 2) uf.Unite(id, id + 1);
}
foreach (var ok in pos[k])
{
uf.Add_P(pt[ok]);
}
OutL(uf.Ans());
}
}
}
//区間右端と左端を管理
public class ExtUnionFind
{
private int[] parent;
private int[] rank;
private int[] L;
private int[] R;
public ExtUnionFind(int n)
{
parent = new int[n];
rank = new int[n];
L = new int[n];
R = new int[n];
for (var i = 0; i < n; i++)
{
parent[i] = i;
L[i] = i;
R[i] = i;
}
}
public int Root(int x)
{
return parent[x] == x ? x : parent[x] = Root(parent[x]);
}
public bool SameRoot(int x, int y)
{
return Root(x) == Root(y);
}
public void Unite(int x, int y)
{
x = Root(x);
y = Root(y);
if (x == y) { return; }
if (rank[x] < rank[y])
{
parent[x] = y;
L[y] = Min(L[x], L[y]);
R[y] = Max(R[x], R[y]);
}
else
{
parent[y] = x;
if (rank[x] == rank[y]) { rank[x]++; }
L[x] = Min(L[x], L[y]);
R[x] = Max(R[x], R[y]);
}
}
public int Lef(int x) => L[Root(x)];
public int Rig(int x) => R[Root(x)];
}
//サイズと属するペア数を管理
public class ExtUnionFind2
{
private int[] parent;
private int[] rank;
private int[] size;
private int[] P;
private long ans;
public ExtUnionFind2(int n)
{
parent = new int[n];
rank = new int[n];
size = new int[n];
P = new int[n];
ans = 0;
for (var i = 0; i < n; i++)
{
parent[i] = i;
size[i] = 1;
}
}
public int Root(int x)
{
return parent[x] == x ? x : parent[x] = Root(parent[x]);
}
public bool SameRoot(int x, int y)
{
return Root(x) == Root(y);
}
public void Unite(int x, int y)
{
x = Root(x);
y = Root(y);
if (x == y) { return; }
ans -= Score(x) + Score(y);
if (rank[x] < rank[y])
{
parent[x] = y;
size[y] += size[x];
P[y] += P[x];
}
else
{
parent[y] = x;
if (rank[x] == rank[y]) { rank[x]++; }
size[x] += size[y];
P[x] += P[y];
}
ans += Score(x);
}
public int SizeOf(int x)
{
return size[Root(x)];
}
public void Add_P(int x)
{
ans -= Score(x);
P[Root(x)]++;
ans += Score(x);
}
public int Score(int x) => Min(size[Root(x)], P[Root(x)]);
public long Ans() => ans;
}
public struct Edge
{
public int from, to;
public long w;
public double dw;
public Edge(int to, long weight) { this.to = to; w = weight; from = -1; dw = -1; }
public Edge(int from, int to, long weight) { this.from = from; this.to = to; w = weight; dw = -1; }
public Edge(int to, double weight) { this.to = to; from = -1; w = -1; dw = weight; }
}
static class Cin
{
public static string[] ReadSplit => Console.ReadLine().Split();
public static int[] ReadSplitInt => ConvertAll(ReadSplit, int.Parse);
public static long[] ReadSplitLong => ConvertAll(ReadSplit, long.Parse);
public static double[] ReadSplit_Double => ConvertAll(ReadSplit, double.Parse);
public static string Str => Console.ReadLine();
public static int Int => int.Parse(Console.ReadLine());
public static long Long => long.Parse(Console.ReadLine());
public static double Double => double.Parse(Console.ReadLine());
public static T Conv<T>(string input)
{
/*if (typeof(T).Equals(typeof(ModInt)))
{
return (T)(dynamic)(long.Parse(input));
}*/
return (T)Convert.ChangeType(input, typeof(T));
}
public static void Scanf<T>(out T a) => a = Conv<T>(Console.ReadLine());
public static void Scanf<T, U>(out T a, out U b)
{ var q = ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); }
public static void Scanf<T, U, V>(out T a, out U b, out V c)
{ var q = ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); }
public static void Scanf<T, U, V, W>(out T a, out U b, out V c, out W d)
{ var q = ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); d = Conv<W>(q[3]); }
public static void Scanf<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
{ var q = ReadSplit; a = Conv<T>(q[0]); b = Conv<U>(q[1]); c = Conv<V>(q[2]); d = Conv<W>(q[3]); e = Conv<X>(q[4]); }
}
static class Cout
{
public static void OutL(object s) => Console.WriteLine(s);
public static void Out_Sep<T>(IEnumerable<T> s) => Console.WriteLine(string.Join(" ", s));
public static void Out_Sep<T>(IEnumerable<T> s, string sep) => Console.WriteLine(string.Join($"{sep}", s));
public static void Out_Sep(params object[] s) => Console.WriteLine(string.Join(" ", s));
public static void Out_One(object s) => Console.Write($"{s} ");
public static void Out_One(object s, string sep) => Console.Write($"{s}{sep}");
public static void Endl() => Console.WriteLine();
}
public static class Tool
{
static public void Initialize<T>(ref T[] array, T initialvalue)
{
array = ConvertAll(array, x => initialvalue);
}
static public void Swap<T>(ref T a, ref T b)
{
T keep = a;
a = b;
b = keep;
}
static public void Display<T>(T[,] array2d, int n, int m)
{
for (var i = 0; i < n; i++)
{
for (var j = 0; j < m; j++)
{
Console.Write($"{array2d[i, j]} ");
}
Console.WriteLine();
}
}
static public long Gcd(long a, long b)
{
if (a == 0 || b == 0) return Max(a, b);
return a % b == 0 ? b : Gcd(b, a % b);
}
static public long LPow(int a, int b) => (long)Pow(a, b);
static public bool Bit(long x, int dig) => ((1L << dig) & x) != 0;
static public int Sig(long a) => a == 0 ? 0 : (int)(a / Abs(a));
}
}
eSeF