Submission #337954

#TimeUsernameProblemLanguageResultExecution timeMemory
337954gmyuSynchronization (JOI13_synchronization)C++14
100 / 100
2756 ms32484 KiB
/* ID: USACO_template LANG: C++ PROG: https://oj.uz/problem/view/JOI13_synchronization Solution: https://bits-and-bytes.me/2020/01/05/JOI-2013-Synchronisation/ */ #include <iostream> //cin , cout #include <fstream> //fin, fout #include <stdio.h> // scanf , pringf #include <cstdio> #include <algorithm> // sort , stuff #include <stack> // stacks #include <queue> // queues #include <map> #include <string> using namespace std; typedef pair<int, int> pii; typedef vector<int> vi; /// adjlist without weight typedef vector<pii> vii; /// adjlist with weight typedef vector<pair<int,pii>> vpip; /// edge with weight typedef long long ll; #define mp make_pair #define fst first #define snd second #define pb push_back #define sz(x) (int)(x).size() #define trav(u, adj_v) for (auto& u: adj_v) const int MOD = 1e9+7; // 998244353; const int MX = 2e5+5; // const ll INF = 1e18; // #define MAXV 100007 #define MAXE 100007 /// code from USACO examples void setIO(string name) { ios_base::sync_with_stdio(0); cin.tie(0); } bool debug = false, submit = true; int N, M, Q; vii edge; vi active; int dp[MAXV], dp0[MAXV]; /** lazy segment tree * Description: 1D range increment and sum query. * Source: USACO Counting Haybales * Verification: SPOJ Horrible */ #define MAXSEGSZ1E5 131072 // 2^17 for 1e5, #define MAXSEGSZ2E5 262144 // 2^18 for 2e5, #define MAXSEGSZ5E5 524288 // 2^19 for 5e5, template<class T, int SZ> struct LazySeg { //static_assert(pct(SZ) == 1); /// SZ must be power of 2 const T ID = 0; T comb(T a, T b) { return (a + b); } /// this depends on operation you want T seg[2*SZ]; LazySeg() { for(int i=0; i<2*SZ; i++) seg[i] = ID; } void initTree(int lo, int hi, int ind=1, int L=0, int R=SZ-1) { if (lo > R || L > hi) return; /// this depends on operation you want if(L==R) { seg[ind] = 1; return; } int M = (L+R)/2; initTree(lo,hi,2*ind,L,M); initTree(lo,hi,2*ind+1,M+1,R); seg[ind] = seg[2*ind] + seg[2*ind+1]; } void updNode(int vtx,T val,int ind=1,int L=0, int R=SZ-1) { /// counting 0 .. SZ-1 if(L == R) {seg[ind] = val; return; } int M = (L+R)/2; (vtx <= M) ? updNode(vtx,val,2*ind,L,M) : updNode(vtx,val,2*ind+1,M+1,R); seg[ind] = seg[2*ind] + seg[2*ind+1]; } T query(int lo, int hi, int ind=1, int L=0, int R=SZ-1) { if (lo > R || L > hi) return 0; /// this depends on operation you want if (lo <= L && R <= hi) return seg[ind]; int M = (L+R)/2; return query(lo,hi,2*ind,L,M) + query(lo,hi,2*ind+1,M+1,R); } }; /** * Description: Heavy-Light Decomposition, add val to verts * and query sum in path/subtree. * Time: any tree path is split into $O(\log N)$ parts * Source: http://codeforces.com/blog/entry/22072, https://codeforces.com/blog/entry/53170 * Verification: * */ #define MAXLCALOG 20 template<int SZ> struct HLD { int edgeOffset = 0; int N; vi adj[SZ]; int par[SZ], root[SZ], depth[SZ], sz[SZ], ti; int pos[SZ]; // pos is bascially its Euler ID, and pos+sz-1 is the end of Euler range vi rpos; // root positions, not used, but could be useful LazySeg<ll,SZ> tree; // segtree for sum int anc[MAXV][MAXLCALOG]; void ae(int x, int y) { adj[x].pb(y), adj[y].pb(x); } void dfsSz(int x) { sz[x] = 1; trav(y,adj[x]) { par[y] = x; depth[y] = depth[x]+1; adj[y].erase(find(adj[y].begin(), adj[y].end(), x)); // remove parent from adj list dfsSz(y); sz[x] += sz[y]; if (sz[y] > sz[adj[x][0]]) swap(y,adj[x][0]); } } void dfsHld(int x) { pos[x] = ti++; rpos.pb(x); // it is travel is Euler walk, and each heavy path is together trav(y,adj[x]) { root[y] = (y == adj[x][0] ? root[x] : y); dfsHld(y); } } void prepLCA(int r) { for(int i = r; i <= N; i++) anc[i][0] = par[i]; for(int j = 1; j < MAXLCALOG; j++) for(int i = r; i <= N; i++) anc[i][j] = anc[anc[i][j-1]][j-1]; } void init(int _N, int R = 1) { N = _N; par[R] = depth[R] = ti = 0; dfsSz(R); root[R] = R; dfsHld(R); prepLCA(R); tree.initTree(0, N-1); } int lca(int x, int y) { for (; root[x] != root[y]; y = par[root[y]]) if (depth[root[x]] > depth[root[y]]) swap(x,y); return depth[x] < depth[y] ? x : y; } int findAnc(int x) { int curr = x; for(int k = MAXLCALOG - 1; k>=0; k--) { int p = anc[curr][k]; if(p==0) continue; if(queryPath(curr, p) - queryPath(p, p) > 0) continue; /// the path has a broken line curr = p; } return curr; } void updTreeNode(int x, int val) { tree.updNode(pos[x], val); } // int dist(int x, int y) { // # edges on path // return depth[x]+depth[y]-2*depth[lca(x,y)]; } void modifyPath(int x, int y, int v) { for (; root[x] != root[y]; y = par[root[y]]) { if (depth[root[x]] > depth[root[y]]) swap(x,y); tree.upd(pos[root[y]],pos[y],v); } if (depth[x] > depth[y]) swap(x,y); tree.upd(pos[x]+edgeOffset,pos[y],v); } ll queryPath(int x, int y) { /// query operation needs to be updated ll res = 0; for (; root[x] != root[y]; y = par[root[y]]) { if (depth[root[x]] > depth[root[y]]) swap(x,y); res += tree.query(pos[root[y]],pos[y]); } if (depth[x] > depth[y]) swap(x,y); res += tree.query(pos[x]+edgeOffset,pos[y]); return res; } void modifySubtree(int x, int v) { tree.upd(pos[x]+edgeOffset,pos[x]+sz[x]-1,v); } }; HLD<MAXSEGSZ1E5> myHld; int main() { debug = false; submit = false; if(submit) setIO("testName"); int i, j, k; int ans = 0; cin >> N >> M >> Q; for(i=1; i<=N-1; i++) { int a, b; cin >> a >> b; edge.pb(mp(a, b)); active.pb(0); myHld.ae(a, b); } myHld.init(N, 1); for(i=1; i<=N; i++) { dp[i] = 1; dp0[i] = 0; } for(i=0; i<M;i++) { int x; cin >> x; x--; int a = edge[x].fst, b = edge[x].snd; if(myHld.depth[a] > myHld.depth[b]) swap(a, b); int pa = myHld.findAnc(a); if(active[x] == 0) { // now connect dp[a] = dp[pa]; dp[a] = dp[a] + dp[b] - dp0[b]; dp[pa] = dp[a]; myHld.updTreeNode(b, 0); active[x] = 1; if(debug) cout << "connect " << a << " " << b << " top at " << myHld.findAnc(b) << endl; } else { // need to disconnect dp0[b] = dp[pa]; dp[b] = dp[pa]; dp[a] = dp[pa]; myHld.updTreeNode(b, 1); active[x] = 0; if(debug) cout << "disconnect " << a << " " << b << " top at " << myHld.findAnc(b) << endl; } } for(i=0; i < Q; i++){ int a; cin >> a; int pa = myHld.findAnc(a); if(debug) cout << " anc is " << pa << endl; cout << dp[pa] << endl; } }

Compilation message (stderr)

synchronization.cpp: In function 'int main()':
synchronization.cpp:182:12: warning: unused variable 'j' [-Wunused-variable]
  182 |     int i, j, k;
      |            ^
synchronization.cpp:182:15: warning: unused variable 'k' [-Wunused-variable]
  182 |     int i, j, k;
      |               ^
synchronization.cpp:183:9: warning: unused variable 'ans' [-Wunused-variable]
  183 |     int ans = 0;
      |         ^~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...