結果
問題 | No.772 Dynamic Distance Sum |
ユーザー | HIR180 |
提出日時 | 2020-04-14 09:30:44 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 1,392 ms / 5,000 ms |
コード長 | 6,444 bytes |
コンパイル時間 | 3,863 ms |
コンパイル使用メモリ | 231,144 KB |
実行使用メモリ | 126,940 KB |
最終ジャッジ日時 | 2024-10-01 16:50:37 |
合計ジャッジ時間 | 25,170 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,248 KB |
testcase_02 | AC | 2 ms
5,248 KB |
testcase_03 | AC | 2 ms
5,248 KB |
testcase_04 | AC | 8 ms
5,248 KB |
testcase_05 | AC | 5 ms
5,248 KB |
testcase_06 | AC | 6 ms
5,248 KB |
testcase_07 | AC | 4 ms
5,248 KB |
testcase_08 | AC | 6 ms
5,248 KB |
testcase_09 | AC | 10 ms
5,248 KB |
testcase_10 | AC | 7 ms
5,248 KB |
testcase_11 | AC | 5 ms
5,248 KB |
testcase_12 | AC | 1,392 ms
125,024 KB |
testcase_13 | AC | 1,277 ms
124,544 KB |
testcase_14 | AC | 803 ms
102,340 KB |
testcase_15 | AC | 989 ms
81,664 KB |
testcase_16 | AC | 752 ms
90,336 KB |
testcase_17 | AC | 1,211 ms
121,088 KB |
testcase_18 | AC | 379 ms
70,400 KB |
testcase_19 | AC | 1,311 ms
124,160 KB |
testcase_20 | AC | 349 ms
70,940 KB |
testcase_21 | AC | 1,260 ms
126,940 KB |
testcase_22 | AC | 1,244 ms
119,936 KB |
testcase_23 | AC | 808 ms
110,004 KB |
testcase_24 | AC | 995 ms
87,168 KB |
testcase_25 | AC | 778 ms
94,372 KB |
testcase_26 | AC | 1,132 ms
118,016 KB |
testcase_27 | AC | 596 ms
84,268 KB |
testcase_28 | AC | 1,201 ms
118,912 KB |
testcase_29 | AC | 343 ms
73,920 KB |
ソースコード
//Let's join Kaede Takagaki Fan Club !! #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> using namespace std; typedef long long ll; typedef pair<int,int> P; typedef pair<int,P> P1; typedef pair<P,P> P2; #define pu push #define pb push_back #define mp make_pair #define eps 1e-7 #define INF 1000000000 #define fi first #define sc second #define rep(i,x) for(int i=0;i<x;i++) #define repn(i,x) for(int i=1;i<=x;i++) #define SORT(x) sort(x.begin(),x.end()) #define ERASE(x) x.erase(unique(x.begin(),x.end()),x.end()) #define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin()) #define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin()) #define all(x) x.begin(),x.end() template<class T> void dmp(T a){ rep(i,a.size()) cout << a[i] << " "; cout << endl; } template<class T> bool chmax(T&a, T b){ if(a < b){ a = b; return 1; } return 0; } template<class T> bool chmin(T&a, T b){ if(a > b){ a = b; return 1; } return 0; } template<class T> void g(T &a){ cin >> a; } template<class T> void o(const T &a,bool space=false){ cout << a << (space?' ':'\n'); } //ios::sync_with_stdio(false); const ll mod = 1000000007;//998244353 template<class T> void add(T&a,T b){ a+=b; if(a >= mod) a-=mod; } //cnt1...部分木に存在する1の頂点の個数 //sum... "splay木においての"部分木に存在する辺の長さの総和 //sum1... 部分木に存在する1の頂点からsplay木の一番上の頂点への距離の総和 //sum2... 部分木に存在する1の頂点からsplay木の一番下の頂点への距離の総和 struct dat { int cnt1; ll sum, sum1, sum2; //reverseする void rv(){ swap(sum1, sum2); } }; struct node{ node *l, *r, *p; int id, rev; dat D, L, S; priority_queue<P>ins, del; node(int i, int c, int w) : l(0), r(0), p(0), id(i), rev(0){ D = S = {c, w, w, w}; L = {0, 0, 0, 0}; } }; inline bool is_root(node *n){ return n -> p == NULL || n -> p -> l != n && n -> p -> r != n; } inline bool left(node *n){ return n == n -> p -> l; } //遅延評価 //push(n)を走らせた後にはn->l と n->r の値は正しく計算されている必要あり inline void push(node *n){ if(n->rev){ swap(n->l, n->r); if(n->l){ n->l->rev ^= 1; n->l->D.rv(); } if(n->r){ n->r->rev ^= 1; n->r->D.rv(); } n->rev = 0; } } //値の再計算 inline void update(node *n){ //最初に遅延評価 push(n); //この2つは簡単 n->D.cnt1 = (n->l?n->l->D.cnt1:0) + (n->r?n->r->D.cnt1:0) + n->L.cnt1 + n->S.cnt1; n->D.sum = (n->l?n->l->D.sum:0) + (n->r?n->r->D.sum:0) + n->S.sum; //根気 n->D.sum1 = 0; if(n->l) n->D.sum1 += n->l->D.sum1; if(n->r) n->D.sum1 += n->r->D.sum1 + 1LL*(n->S.sum+(n->l?n->l->D.sum:0)) * n->r->D.cnt1; if(n->S.cnt1) n->D.sum1 += 1LL*(n->S.sum+(n->l?n->l->D.sum:0)); n->D.sum1 += n->L.sum1 + 1LL*(n->S.sum+(n->l?n->l->D.sum:0)) * n->L.cnt1; n->D.sum2 = 0; if(n->l) n->D.sum2 += n->l->D.sum2 + 1LL*(n->S.sum+(n->r?n->r->D.sum:0)) * n->l->D.cnt1; if(n->r) n->D.sum2 += n->r->D.sum2; if(n->S.cnt1) n->D.sum2 += 1LL*(n->S.sum+(n->r?n->r->D.sum:0)); n->D.sum2 += n->L.sum1 + 1LL*(n->S.sum+(n->r?n->r->D.sum:0)) * n->L.cnt1; } inline void connect(node *n, node *p, bool l){ (l ? p -> l : p -> r) = n; if(n) n -> p = p; } //rotateが呼ばれる前には関与しているノードの遅延評価をする必要がある inline void rotate(node *n){ node *p = n -> p, *g = p -> p; bool l = left(n); connect(l ? n -> r : n -> l, p, l); if(!is_root(p)) connect(n, g, left(p)); else{ //light edgeを繋ぎ変える if(g){ g->del.push(mp(p->D.cnt1, p->id)); g->ins.push(mp(p->D.cnt1, n->id)); } n -> p = g; } connect(p, n, !l); update(p), update(n); } inline void splay(node *n){ if(is_root(n)){ update(n); return; } while(!is_root(n)){ node *p = n -> p, *g = p -> p; //関与する頂点群の遅延評価をする if(!is_root(p)) push(g); push(p), push(n); if(!is_root(p)) rotate(left(n) ^ left(p) ? n : p); rotate(n); } } //返り値はnじゃないよ //部分木クエリの時は適切に更新 inline node* expose(node *n){ node *last = NULL; for(node *m = n; m; m = m -> p){ splay(m); if(m->r) { m->L.cnt1 += m->r->D.cnt1; m->L.sum1 += m->r->D.sum1; m->ins.push(mp(m->r->D.cnt1, m->r->id)); } m -> r = last; if(m->r) { m->L.cnt1 -= m->r->D.cnt1; m->L.sum1 -= m->r->D.sum1; m->del.push(mp(m->r->D.cnt1, m->r->id)); } update(m); last = m; } splay(n); return last; } //部分木クエリの時は適切に更新 inline void link(node *m, node *n){ expose(m), expose(n); m -> p = n; n->L.cnt1 += m->D.cnt1; n->L.sum1 += m->D.sum1; n->ins.push(mp(m->D.cnt1, m->id)); update(n); } inline node* find_root(node *n){ if(!n) return (node*)NULL; while(1){ push(n); if(n->r) n = n->r; else break; } return n; } inline node* cut(node *n){ expose(n); node *ret = n->l; n -> l -> p = NULL; n -> l = NULL; update(n); return find_root(ret); } //nを根に持っていく //updateは必要ない inline void evert(node *n){ expose(n); n->rev ^= 1; n->D.rv(); } const int MAXN = 300005; node *V[MAXN]; int find(node *n, int sz){ int lim = (sz+1)/2; while(1){ push(n); if(n->r && n->r->D.cnt1 >= lim) n = n->r; else if(n->l && n->D.cnt1 - n->l->D.cnt1 < lim){ lim -= (n->D.cnt1-n->l->D.cnt1); n = n->l; } else{ while(n->del.size() && n->ins.size() && n->del.top() == n->ins.top() && n->ins.top().fi >= (sz+1)/2){ n->del.pop(); n->ins.pop(); } if(n->ins.size() && n->ins.top().fi >= (sz+1)/2){ lim = (sz+1)/2; n = V[n->ins.top().sc]; } else return n->id; } } } int n, q; ll sum; int nxt = 100001; int main(){ scanf("%d%d",&n, &q); repn(i, n) V[i] = new node(i, 1, 0); rep(i, q){ int ty; scanf("%d",&ty); if(ty == 1){ int a, b, c; scanf("%d%d%d",&a,&b,&c); a = (a-1+sum)%n+1; b = (b-1+sum)%n+1; evert(V[a]); V[nxt] = new node(nxt, 0, c); link(V[a], V[nxt]); link(V[nxt], V[b]); nxt++; } else if(ty == 2){ int a, b; scanf("%d%d",&a,&b); a = (a-1+sum)%n+1; b = (b-1+sum)%n+1; evert(V[a]); node *mid = cut(V[b]); cut(mid); } else{ int a; scanf("%d",&a); a = (a-1+sum)%n+1; evert(V[a]); V[a]->S.cnt1 ^= 1; update(V[a]); ll ans = 1e18; int cent = find(V[a], V[a]->D.cnt1); evert(V[cent]); ans = V[cent]->D.sum1; printf("%lld\n", ans); sum = (sum+ans)%n; } } }