結果
問題 | No.1641 Tree Xor Query |
ユーザー | terry_u16 |
提出日時 | 2021-08-06 22:21:03 |
言語 | C# (.NET 8.0.203) |
結果 |
AC
|
実行時間 | 194 ms / 5,000 ms |
コード長 | 26,474 bytes |
コンパイル時間 | 10,790 ms |
コンパイル使用メモリ | 169,852 KB |
実行使用メモリ | 209,040 KB |
最終ジャッジ日時 | 2024-09-17 02:25:01 |
合計ジャッジ時間 | 12,869 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 61 ms
32,128 KB |
testcase_01 | AC | 60 ms
32,372 KB |
testcase_02 | AC | 62 ms
32,512 KB |
testcase_03 | AC | 58 ms
32,256 KB |
testcase_04 | AC | 57 ms
32,000 KB |
testcase_05 | AC | 58 ms
32,128 KB |
testcase_06 | AC | 57 ms
31,872 KB |
testcase_07 | AC | 59 ms
32,000 KB |
testcase_08 | AC | 60 ms
31,872 KB |
testcase_09 | AC | 61 ms
32,256 KB |
testcase_10 | AC | 60 ms
31,872 KB |
testcase_11 | AC | 58 ms
31,872 KB |
testcase_12 | AC | 57 ms
32,256 KB |
testcase_13 | AC | 194 ms
61,440 KB |
testcase_14 | AC | 190 ms
61,696 KB |
testcase_15 | AC | 61 ms
32,640 KB |
testcase_16 | AC | 68 ms
33,408 KB |
testcase_17 | AC | 65 ms
33,152 KB |
testcase_18 | AC | 64 ms
33,280 KB |
testcase_19 | AC | 60 ms
32,636 KB |
testcase_20 | AC | 161 ms
209,040 KB |
コンパイルメッセージ
復元対象のプロジェクトを決定しています... /home/judge/data/code/main.csproj を復元しました (95 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.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using System.Text; using YukicoderContest308.Problems; namespace YukicoderContest308.Problems { public class ProblemF : ProblemBase { public ProblemF() : base(false) { } [MethodImpl(MethodImplOptions.AggressiveOptimization)] protected override void SolveEach(IOManager io) { var n = io.ReadInt(); var queryCount = io.ReadInt(); var costs = io.ReadIntArray(n); var inIndex = new int[n]; var outIndex = new int[n]; var index = 0; var tree = Enumerable.Repeat(0, n).Select(_ => new List<int>()).ToArray(); for (int i = 0; i < n - 1; i++) { var u = io.ReadInt(); var v = io.ReadInt(); u--; v--; tree[u].Add(v); tree[v].Add(u); } EularTour(0, -1, ref index); var segTree = new SegmentTree<Xor>(2 * n); for (int i = 0; i < inIndex.Length; i++) { segTree[inIndex[i]] = new Xor(costs[i]); } for (int q = 0; q < queryCount; q++) { var type = io.ReadInt(); var x = io.ReadInt(); var y = io.ReadInt(); x--; if (type == 1) { segTree[inIndex[x]] = new Xor(segTree[inIndex[x]].Value ^ y); } else { io.WriteLine(segTree.Query(inIndex[x], outIndex[x]).Value); } } void EularTour(int current, int parent, ref int index) { inIndex[current] = index++; foreach (var child in tree[current]) { if (child == parent) { continue; } EularTour(child, current, ref index); } outIndex[current] = index++; } } readonly struct Xor : IMonoid<Xor> { readonly public int Value; public Xor Identity => new Xor(0); public Xor(int value) { Value = value; } public Xor Merge(Xor other) { return new Xor(Value ^ other.Value); } } public interface ISemigroup<TSet> { public TSet Merge(TSet other); } public interface IMonoid<TSet> : ISemigroup<TSet> { public TSet Identity { get; } } public interface IMonoidWithAct<TMonoid, TOperator> : IMonoid<TOperator> where TMonoid : IMonoid<TMonoid> where TOperator : IMonoid<TOperator> { public TMonoid Act(TMonoid monoid); } public class SegmentTree<T> where T : struct, IMonoid<T> { // 1-indexed protected readonly T[] _data; public int Length { get; } protected Span<T> Leaves => _data.AsSpan(HalfLength, Length); protected int HalfLength => _data.Length >> 1; /// <summary> /// 単位元で初期化します。 /// </summary> public SegmentTree(int n) : this(n, default(T).Identity) { } /// <summary> /// 指定した値で初期化します。 /// </summary> public SegmentTree(int n, T initialValue) { if (n < 0) { throw new ArgumentOutOfRangeException(); } Length = n; _data = new T[1 << (CeilPow2(n) + 1)]; _data.AsSpan(HalfLength, Length).Fill(initialValue); Build(); } /// <summary> /// 指定したデータ列で初期化します。 /// </summary> public SegmentTree(ReadOnlySpan<T> values) { Length = values.Length; _data = new T[1 << (CeilPow2(values.Length) + 1)]; values.CopyTo(Leaves); Build(); } public virtual T this[int index] { get => Leaves[index]; set { Leaves[index] = value; index += HalfLength; while ((index >>= 1) > 0) { _data[index] = _data[(index << 1) + 0].Merge(_data[(index << 1) + 1]); } } } public T Query(Range range) => Query(range.Start, range.End); public T Query(Index left, Index right) => Query(left.GetOffset(Length), right.GetOffset(Length)); public virtual T Query(int left, int right) { if (unchecked((uint)left > (uint)Length || (uint)right > (uint)Length || left > right)) { throw new ArgumentOutOfRangeException(); } var sumL = default(T).Identity; var sumR = default(T).Identity; left += HalfLength; right += HalfLength; while (left < right) { if ((left & 1) > 0) { sumL = sumL.Merge(_data[left++]); } if ((right & 1) > 0) { sumR = _data[--right].Merge(sumR); } left >>= 1; right >>= 1; } return sumL.Merge(sumR); } public T QueryAll() => _data[1]; private void Build() { var parents = HalfLength; _data.AsSpan(parents + Length).Fill(default(T).Identity); for (int i = parents - 1; i >= 0; i--) { _data[i] = _data[(i << 1) + 0].Merge(_data[(i << 1) + 1]); } } /// <summary> /// [l, r)が条件を満たす最大のrを求めます。 /// </summary> public int FindMaxRight(Index left, Predicate<T> predicate) => FindMaxRight(left.GetOffset(Length), predicate); /// <summary> /// [l, r)が条件を満たす最大のrを求めます。 /// </summary> public virtual int FindMaxRight(int left, Predicate<T> predicate) { // 単位元は条件式を満たす必要がある Debug.Assert(predicate(default(T).Identity)); if (unchecked((uint)left > Length)) { throw new ArgumentOutOfRangeException(); } else if (left == Length) { return Length; } var right = left + HalfLength; var sum = default(T).Identity; do { right >>= BitOperations.TrailingZeroCount(right); var merged = sum.Merge(_data[right]); if (!predicate(merged)) { return DownSearch(right, sum, predicate); } sum = merged; right++; } while ((right & -right) != right); return Length; int DownSearch(int right, T sum, Predicate<T> predicate) { while (right < HalfLength) { right <<= 1; var merged = sum.Merge(_data[right]); if (predicate(merged)) { sum = merged; right++; } } return right - HalfLength; } } /// <summary> /// [l, r)が条件を満たす最小のlを求めます。 /// </summary> public int FindMinLeft(Index right, Predicate<T> predicate) => FindMinLeft(right.GetOffset(Length), predicate); /// <summary> /// [l, r)が条件を満たす最小のlを求めます。 /// </summary> public virtual int FindMinLeft(int right, Predicate<T> predicate) { // 単位元は条件式を満たす必要がある Debug.Assert(predicate(default(T).Identity)); if (unchecked((uint)right > Length)) { throw new ArgumentOutOfRangeException(); } else if (right == 0) { return 0; } var left = right + HalfLength; var sum = default(T).Identity; do { left--; left >>= BitOperations.TrailingZeroCount((1 << BitOperations.Log2((uint)left)) | ~left); var merged = _data[left].Merge(sum); if (!predicate(merged)) { return DownSearch(left, sum, predicate); } sum = merged; } while ((left & -left) != left); return 0; int DownSearch(int left, T sum, Predicate<T> predicate) { while (left < HalfLength) { left = (left << 1) + 1; var merged = _data[left].Merge(sum); if (predicate(merged)) { sum = merged; left--; } } return left + 1 - HalfLength; } } protected static int CeilPow2(int n) { var m = (uint)n; if (m <= 1) { return 0; } else { return BitOperations.Log2(m - 1) + 1; } } } } } namespace YukicoderContest308 { class Program { static void Main(string[] args) { IProblem question = new ProblemF(); using var io = new IOManager(Console.OpenStandardInput(), Console.OpenStandardOutput()); question.Solve(io); } } } #region Base Class namespace YukicoderContest308.Problems { public interface IProblem { string Solve(string input); void Solve(IOManager io); } public abstract class ProblemBase : IProblem { protected bool HasMultiTestCases { get; } protected ProblemBase(bool hasMultiTestCases) => HasMultiTestCases = hasMultiTestCases; public string Solve(string input) { var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(input)); var outputStream = new MemoryStream(); using var manager = new IOManager(inputStream, outputStream); Solve(manager); manager.Flush(); outputStream.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(outputStream); return reader.ReadToEnd(); } public void Solve(IOManager io) { var tests = HasMultiTestCases ? io.ReadInt() : 1; for (var t = 0; t < tests; t++) { SolveEach(io); } } protected abstract void SolveEach(IOManager io); } } #endregion #region Utils namespace YukicoderContest308 { public class IOManager : IDisposable { private readonly BinaryReader _reader; private readonly StreamWriter _writer; private bool _disposedValue; private byte[] _buffer = new byte[1024]; private int _length; private int _cursor; private bool _eof; const char ValidFirstChar = '!'; const char ValidLastChar = '~'; public IOManager(Stream input, Stream output) { _reader = new BinaryReader(input); _writer = new StreamWriter(output) { AutoFlush = false }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private char ReadAscii() { if (_cursor == _length) { _cursor = 0; _length = _reader.Read(_buffer); if (_length == 0) { if (!_eof) { _eof = true; return char.MinValue; } else { ThrowEndOfStreamException(); } } } return (char)_buffer[_cursor++]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public char ReadChar() { char c; while (!IsValidChar(c = ReadAscii())) { } return c; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadString() { var builder = new StringBuilder(); char c; while (!IsValidChar(c = ReadAscii())) { } do { builder.Append(c); } while (IsValidChar(c = ReadAscii())); return builder.ToString(); } public int ReadInt() => (int)ReadLong(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public long ReadLong() { long result = 0; bool isPositive = true; char c; while (!IsNumericChar(c = ReadAscii())) { } if (c == '-') { isPositive = false; c = ReadAscii(); } do { result *= 10; result += c - '0'; } while (IsNumericChar(c = ReadAscii())); return isPositive ? result : -result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Span<char> ReadChunk(Span<char> span) { var i = 0; char c; while (!IsValidChar(c = ReadAscii())) { } do { span[i++] = c; } while (IsValidChar(c = ReadAscii())); return span.Slice(0, i); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public double ReadDouble() => double.Parse(ReadChunk(stackalloc char[32])); [MethodImpl(MethodImplOptions.AggressiveInlining)] public decimal ReadDecimal() => decimal.Parse(ReadChunk(stackalloc char[32])); public int[] ReadIntArray(int n) { var a = new int[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadInt(); } return a; } public long[] ReadLongArray(int n) { var a = new long[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadLong(); } return a; } public double[] ReadDoubleArray(int n) { var a = new double[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadDouble(); } return a; } public decimal[] ReadDecimalArray(int n) { var a = new decimal[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadDecimal(); } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write<T>(T value) => _writer.Write(value.ToString()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteLine<T>(T value) => _writer.WriteLine(value.ToString()); public void WriteLine<T>(IEnumerable<T> values, char separator) { var e = values.GetEnumerator(); if (e.MoveNext()) { _writer.Write(e.Current.ToString()); while (e.MoveNext()) { _writer.Write(separator); _writer.Write(e.Current.ToString()); } } _writer.WriteLine(); } public void WriteLine<T>(T[] values, char separator) => WriteLine((ReadOnlySpan<T>)values, separator); public void WriteLine<T>(Span<T> values, char separator) => WriteLine((ReadOnlySpan<T>)values, separator); public void WriteLine<T>(ReadOnlySpan<T> values, char separator) { for (int i = 0; i < values.Length - 1; i++) { _writer.Write(values[i]); _writer.Write(separator); } if (values.Length > 0) { _writer.Write(values[^1]); } _writer.WriteLine(); } public void Flush() => _writer.Flush(); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsValidChar(char c) => ValidFirstChar <= c && c <= ValidLastChar; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNumericChar(char c) => ('0' <= c && c <= '9') || c == '-'; private void ThrowEndOfStreamException() => throw new EndOfStreamException(); protected virtual void Dispose(bool disposing) { if (!_disposedValue) { if (disposing) { _reader.Dispose(); _writer.Flush(); _writer.Dispose(); } _disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public static class UtilExtensions { public static bool ChangeMax<T>(ref this T value, T other) where T : struct, IComparable<T> { if (value.CompareTo(other) < 0) { value = other; return true; } return false; } public static bool ChangeMin<T>(ref this T value, T other) where T : struct, IComparable<T> { if (value.CompareTo(other) > 0) { value = other; return true; } return false; } public static void SwapIfLargerThan<T>(ref this T a, ref T b) where T : struct, IComparable<T> { if (a.CompareTo(b) > 0) { (a, b) = (b, a); } } public static void SwapIfSmallerThan<T>(ref this T a, ref T b) where T : struct, IComparable<T> { if (a.CompareTo(b) < 0) { (a, b) = (b, a); } } public static void Sort<T>(this T[] array) where T : IComparable<T> => Array.Sort(array); public static void Sort<T>(this T[] array, Comparison<T> comparison) => Array.Sort(array, comparison); } public static class CollectionExtensions { private class ArrayWrapper<T> { #pragma warning disable CS0649 public T[] Array; #pragma warning restore CS0649 } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> AsSpan<T>(this List<T> list) { return Unsafe.As<ArrayWrapper<T>>(list).Array.AsSpan(0, list.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> GetRowSpan<T>(this T[,] array, int i) { var width = array.GetLength(1); return MemoryMarshal.CreateSpan(ref array[i, 0], width); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> GetRowSpan<T>(this T[,,] array, int i, int j) { var width = array.GetLength(2); return MemoryMarshal.CreateSpan(ref array[i, j, 0], width); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> GetRowSpan<T>(this T[,,,] array, int i, int j, int k) { var width = array.GetLength(3); return MemoryMarshal.CreateSpan(ref array[i, j, k, 0], width); } public static void Fill<T>(this T[] array, T value) => array.AsSpan().Fill(value); public static void Fill<T>(this T[,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0], array.Length).Fill(value); public static void Fill<T>(this T[,,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0, 0], array.Length).Fill(value); public static void Fill<T>(this T[,,,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0, 0, 0], array.Length).Fill(value); } public static class SearchExtensions { struct LowerBoundComparer<T> : IComparer<T> where T : IComparable<T> { public int Compare(T x, T y) => 0 <= x.CompareTo(y) ? 1 : -1; } struct UpperBoundComparer<T> : IComparer<T> where T : IComparable<T> { public int Compare(T x, T y) => 0 < x.CompareTo(y) ? 1 : -1; } // https://trsing.hatenablog.com/entry/2019/08/27/211038 public static int GetGreaterEqualIndex<T>(this ReadOnlySpan<T> span, T inclusiveMin) where T : IComparable<T> => ~span.BinarySearch(inclusiveMin, new UpperBoundComparer<T>()); public static int GetGreaterThanIndex<T>(this ReadOnlySpan<T> span, T exclusiveMin) where T : IComparable<T> => ~span.BinarySearch(exclusiveMin, new LowerBoundComparer<T>()); public static int GetLessEqualIndex<T>(this ReadOnlySpan<T> span, T inclusiveMax) where T : IComparable<T> => ~span.BinarySearch(inclusiveMax, new LowerBoundComparer<T>()) - 1; public static int GetLessThanIndex<T>(this ReadOnlySpan<T> span, T exclusiveMax) where T : IComparable<T> => ~span.BinarySearch(exclusiveMax, new UpperBoundComparer<T>()) - 1; public static int GetGreaterEqualIndex<T>(this Span<T> span, T inclusiveMin) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetGreaterEqualIndex(inclusiveMin); public static int GetGreaterThanIndex<T>(this Span<T> span, T exclusiveMin) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetGreaterThanIndex(exclusiveMin); public static int GetLessEqualIndex<T>(this Span<T> span, T inclusiveMax) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetLessEqualIndex(inclusiveMax); public static int GetLessThanIndex<T>(this Span<T> span, T exclusiveMax) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetLessThanIndex(exclusiveMax); public static int BoundaryBinarySearch(Predicate<int> predicate, int ok, int ng) { while (Math.Abs(ok - ng) > 1) { var mid = (ok + ng) / 2; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return ok; } public static long BoundaryBinarySearch(Predicate<long> predicate, long ok, long ng) { while (Math.Abs(ok - ng) > 1) { var mid = (ok + ng) / 2; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return ok; } public static BigInteger BoundaryBinarySearch(Predicate<BigInteger> predicate, BigInteger ok, BigInteger ng) { while (BigInteger.Abs(ok - ng) > 1) { var mid = (ok + ng) / 2; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return ok; } public static double BoundaryBinarySearch(Predicate<double> predicate, double ok, double ng, double eps = 1e-9, int loopLimit = 1000) { var count = 0; while (Math.Abs(ok - ng) > eps && count++ < loopLimit) { var mid = (ok + ng) * 0.5; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return (ok + ng) * 0.5; } public static double Bisection(Func<double, double> f, double a, double b, double eps = 1e-9, int loopLimit = 100) { double mid = (a + b) / 2; var fa = f(a); if (fa * f(b) >= 0) { throw new ArgumentException("f(a)とf(b)は異符号である必要があります。"); } for (int i = 0; i < loopLimit; i++) { var fmid = f(mid); var sign = fa * fmid; if (sign < 0) { b = mid; } else if (sign > 0) { a = mid; fa = fmid; } else { return mid; } mid = (a + b) / 2; if (Math.Abs(b - a) < eps) { break; } } return mid; } } } #endregion