結果

問題 No.1054 Union add query
ユーザー 回転
提出日時 2025-09-13 00:20:11
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 692 ms / 2,000 ms
コード長 9,726 bytes
コンパイル時間 3,623 ms
コンパイル使用メモリ 294,368 KB
実行使用メモリ 90,112 KB
最終ジャッジ日時 2025-09-13 00:20:21
合計ジャッジ時間 9,272 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 8
権限があれば一括ダウンロードができます

ソースコード

diff #

/*
from collections import defaultdict

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n
        self.retu = [[i] for i in range(n)]

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

        if(len(self.retu[x]) <= len(self.retu[y])):
            for i in self.retu[x]:
                self.retu[y].append(i)
            self.retu[x],self.retu[y] = self.retu[y],self.retu[x]
        else:
            for i in self.retu[y]:
                self.retu[x].append(i)

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        group_members = defaultdict(list)
        for member in range(self.n):
            group_members[self.find(member)].append(member)
        return group_members

    def __str__(self):
        return '\n'.join(f'{r}: {m}' for r, m in self.all_group_members().items())

def segfunc(x,y):
    return x+y
class LazySegTree_RAQ:
    def __init__(self,init_val,segfunc,ide_ele):
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1<<(n-1).bit_length()
        self.tree = [ide_ele]*2*self.num
        self.lazy = [0]*2*self.num
        for i in range(n):
            self.tree[self.num+i] = init_val[i]
        for i in range(self.num-1,0,-1):
            self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1])
    def gindex(self,l,r):
        l += self.num
        r += self.num
        lm = l>>(l&-l).bit_length()
        rm = r>>(r&-r).bit_length()
        while r>l:
            if l<=lm:
                yield l
            if r<=rm:
                yield r
            r >>= 1
            l >>= 1
        while l:
            yield l
            l >>= 1
    def propagates(self,*ids):
        for i in reversed(ids):
            v = self.lazy[i]
            if v==0:
                continue
            self.lazy[i] = 0
            self.lazy[2*i] += v
            self.lazy[2*i+1] += v
            self.tree[2*i] += v
            self.tree[2*i+1] += v
    def add(self,l,r,x):
        ids = self.gindex(l,r)
        l += self.num
        r += self.num
        while l<r:
            if l&1:
                self.lazy[l] += x
                self.tree[l] += x
                l += 1
            if r&1:
                self.lazy[r-1] += x
                self.tree[r-1] += x
            r >>= 1
            l >>= 1
        for i in ids:
            self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1]) + self.lazy[i]
    def query(self,l,r):
        self.propagates(*self.gindex(l,r))
        res = self.ide_ele
        l += self.num
        r += self.num
        while l<r:
            if l&1:
                res = self.segfunc(res,self.tree[l])
                l += 1
            if r&1:
                res = self.segfunc(res,self.tree[r-1])
            l >>= 1
            r >>= 1
        return res

from collections import defaultdict
import sys
input = sys.stdin.readline
N,Q = list(map(int,input().split()))
query = [list(map(int,input().split())) for _ in range(Q)]

uf = UnionFind(N)
for i in range(Q):
    t,a,b, = query[i]
    a -= 1;b -= 1
    if(t == 1):uf.union(a,b)

v = []
done = set()
for p in uf.roots():
    if(p in done):continue
    done.add(p)
    v += uf.retu[p]

place = [-1 for _ in range(N)]
for i in range(N):place[v[i]] = i

uf = UnionFind(N)
T = LazySegTree_RAQ([0 for _ in range(N)],segfunc,0)
for i in range(Q):
    t,a,b, = query[i]
    if(t == 1):
        uf.union(a-1,b-1)
    elif(t == 2):
        ap = uf.find(a-1)
        head = uf.retu[ap][0]
        end = uf.retu[ap][-1]
        T.add(place[head],place[end]+1,b) 
    else:
        p = place[a-1]
        print(T.query(p,p+1))
*/

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

// ---------- UnionFind (retu を保持) ----------
struct UnionFind {
    int n;
    vector<int> parents;            // negative size for root
    vector<vector<int>> retu;       // members lists per root-index

    UnionFind(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        parents.assign(n, -1);
        retu.assign(n, vector<int>());
        for (int i = 0; i < n; ++i) retu[i].push_back(i);
    }

    int find(int x) {
        if (parents[x] < 0) return x;
        return parents[x] = find(parents[x]);
    }

    void unite(int x, int y) {
        x = find(x); y = find(y);
        if (x == y) return;
        // ensure x is the bigger (more negative)
        if (parents[x] > parents[y]) swap(x, y);
        parents[x] += parents[y];
        parents[y] = x;

        // merge retu exactly like Python version
        if (retu[x].size() <= retu[y].size()) {
            // append retu[x] into retu[y], then swap so retu[x] becomes combined list
            for (int v : retu[x]) retu[y].push_back(v);
            retu[x].swap(retu[y]);
        } else {
            for (int v : retu[y]) retu[x].push_back(v);
        }
    }

    int size(int x) { return -parents[find(x)]; }

    bool same(int x, int y) { return find(x) == find(y); }

    vector<int> roots() {
        vector<int> res;
        for (int i = 0; i < n; ++i) if (parents[i] < 0) res.push_back(i);
        return res;
    }
};

// ---------- Lazy Segment Tree (range add, range sum) ----------
// Implemented with standard recursive lazy propagation
struct LazySegTreeRAQ {
    int n;
    vector<ll> seg;   // segment sums
    vector<ll> lz;    // lazy addition (to add to children)
    LazySegTreeRAQ() { n = 0; }
    LazySegTreeRAQ(int _n) { build(_n); }
    LazySegTreeRAQ(const vector<ll>& init) { build(init); }

    void build(int _n) {
        n = 1;
        while (n < _n) n <<= 1;
        seg.assign(2*n, 0);
        lz.assign(2*n, 0);
    }
    void build(const vector<ll>& init) {
        int m = (int)init.size();
        n = 1;
        while (n < m) n <<= 1;
        seg.assign(2*n, 0);
        lz.assign(2*n, 0);
        for (int i = 0; i < m; ++i) seg[n+i] = init[i];
        for (int i = n-1; i >= 1; --i) seg[i] = seg[2*i] + seg[2*i+1];
    }

    void push(int k, int l, int r) {
        if (lz[k] != 0 && k < n) {
            ll v = lz[k];
            int mid = (l + r) >> 1;
            // left child covers [l,mid), right [mid,r)
            seg[2*k] += v * (mid - l);
            seg[2*k+1] += v * (r - mid);
            lz[2*k] += v;
            lz[2*k+1] += v;
            lz[k] = 0;
        }
    }

    // add x to [a,b)
    void add(int a, int b, ll x) { add_impl(a,b,x,1,0,n); }
    void add_impl(int a, int b, ll x, int k, int l, int r) {
        if (b <= l || r <= a) return;
        if (a <= l && r <= b) {
            seg[k] += x * (r - l);
            lz[k] += x;
            return;
        }
        push(k,l,r);
        int mid = (l + r) >> 1;
        add_impl(a,b,x,2*k,l,mid);
        add_impl(a,b,x,2*k+1,mid,r);
        seg[k] = seg[2*k] + seg[2*k+1];
    }

    // sum on [a,b)
    ll sum(int a, int b) { return sum_impl(a,b,1,0,n); }
    ll sum_impl(int a, int b, int k, int l, int r) {
        if (b <= l || r <= a) return 0;
        if (a <= l && r <= b) return seg[k];
        push(k,l,r);
        int mid = (l + r) >> 1;
        return sum_impl(a,b,2*k,l,mid) + sum_impl(a,b,2*k+1,mid,r);
    }
};

// ---------- main ----------
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, Q;
    if (!(cin >> N >> Q)) return 0;
    vector<array<int,3>> query(Q);
    for (int i = 0; i < Q; ++i) {
        int t, a, b;
        cin >> t >> a >> b;
        query[i] = {t, a, b};
    }

    // 1st pass: build components by applying all t==1 unions
    UnionFind uf1(N);
    for (int i = 0; i < Q; ++i) {
        int t = query[i][0], a = query[i][1], b = query[i][2];
        if (t == 1) {
            uf1.unite(a-1, b-1);
        }
    }

    // collect v by concatenating retu of roots (same as Python)
    vector<int> v;
    vector<int> roots1 = uf1.roots();
    // Python code iterates roots() in increasing order; roots1 is in increasing order
    for (int p : roots1) {
        // append whole retu[p]
        for (int x : uf1.retu[p]) v.push_back(x);
    }

    // place mapping: element -> position in v
    vector<int> place(N, -1);
    for (int i = 0; i < N; ++i) place[v[i]] = i;

    // 2nd pass: process queries incrementally with fresh UnionFind and LazySegTree
    UnionFind uf2(N);
    LazySegTreeRAQ T(N); // length N, initial zeros

    for (int i = 0; i < Q; ++i) {
        int t = query[i][0], a = query[i][1], b = query[i][2];
        if (t == 1) {
            uf2.unite(a-1, b-1);
        } else if (t == 2) {
            int ap = uf2.find(a-1);
            // head and end from retu[ap]
            int head = uf2.retu[ap].front();
            int end = uf2.retu[ap].back();
            // add b to range [place[head], place[end]+1)
            T.add(place[head], place[end] + 1, (ll)b);
        } else if (t == 3) {
            int p = place[a-1];
            cout << T.sum(p, p+1) << '\n';
        }
    }

    return 0;
}
0