Submission #1282897

#TimeUsernameProblemLanguageResultExecution timeMemory
1282897goldencheemsSpring cleaning (CEOI20_cleaning)C++20
0 / 100
124 ms26008 KiB
/*DEP TRAI CO J SAI*/ /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@@@%%##***************************+++++++++++++++++++++++++++++++++++++++++++++++***************************######%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* Template theo yêu cầu: bits, pragma, macros fi/se/pu, typedef ll, hàm tinh(), fast IO. Code: HLD + segment tree để tính sum_e min(leaves_sub_e, L - leaves_sub_e) */ #include <bits/stdc++.h> using namespace std; #pragma GCC optimize ("O3") #pragma GCC optimize ("unroll-loops") #define fi first #define se second #define pu push_back typedef long long ll; const int MAXN = 200000 + 5; // safe bound int n, Q; vector<int> adj[MAXN]; int deg[MAXN]; int parentArr[MAXN], depthArr[MAXN], sz[MAXN]; int heavy[MAXN], head[MAXN], pos[MAXN], curPos; int origLeaf[MAXN]; int subLeaf[MAXN]; int baseVal[MAXN]; // baseVal at pos[u] = subtree leaves of u ll baseSum = 0; void dfs1(int u,int p){ parentArr[u]=p; sz[u]=1; heavy[u]=0; subLeaf[u]= (deg[u]==1 ? 1 : 0); for(int v: adj[u]){ if(v==p) continue; depthArr[v]=depthArr[u]+1; dfs1(v,u); sz[u]+=sz[v]; subLeaf[u]+=subLeaf[v]; if(!heavy[u] || sz[v]>sz[heavy[u]]) heavy[u]=v; } } void dfs_hld(int u,int h){ head[u]=h; pos[u]=++curPos; baseVal[curPos]=subLeaf[u]; if(heavy[u]) dfs_hld(heavy[u],h); for(int v: adj[u]){ if(v==parentArr[u] || v==heavy[u]) continue; dfs_hld(v,v); } } // segment tree for values t_i = baseVal + adds struct Seg{ struct Node{ ll mn, mx, sum; int len; ll lazy; }; vector<Node> st; int n; Seg(int _n=0){init(_n);} void init(int _n){ n=_n; st.assign(4*n+5, {0,0,0,0,0}); } void build(int id,int l,int r){ st[id].lazy=0; st[id].len = r-l+1; if(l==r){ ll v = baseVal[l]; st[id].mn = st[id].mx = st[id].sum = v; return; } int m=(l+r)/2; build(id<<1,l,m); build(id<<1|1,m+1,r); st[id].mn = min(st[id<<1].mn, st[id<<1|1].mn); st[id].mx = max(st[id<<1].mx, st[id<<1|1].mx); st[id].sum = st[id<<1].sum + st[id<<1|1].sum; } void apply(int id, ll val){ st[id].mn += val; st[id].mx += val; st[id].sum += val * st[id].len; st[id].lazy += val; } void push(int id){ if(st[id].lazy!=0){ apply(id<<1, st[id].lazy); apply(id<<1|1, st[id].lazy); st[id].lazy=0; } } void pull(int id){ st[id].mn = min(st[id<<1].mn, st[id<<1|1].mn); st[id].mx = max(st[id<<1].mx, st[id<<1|1].mx); st[id].sum = st[id<<1].sum + st[id<<1|1].sum; } void update(int id,int l,int r,int L,int R,ll val){ if(L>r || R<l) return; if(L<=l && r<=R){ apply(id,val); return; } push(id); int m=(l+r)/2; update(id<<1,l,m,L,R,val); update(id<<1|1,m+1,r,L,R,val); pull(id); } // query number of positions with value > T and sum of those values pair<int,ll> queryGreater(int id,int l,int r,ll T){ if(st[id].mx <= T) return {0,0}; if(st[id].mn > T) return {st[id].len, st[id].sum}; push(id); int m=(l+r)/2; auto L = queryGreater(id<<1,l,m,T); auto R = queryGreater(id<<1|1,m+1,r,T); return {L.first + R.first, L.second + R.second}; } ll totalSum(){ return st[1].sum; } }; Seg seg; void path_update(int u,int v,ll val){ // here v is root (1). we'll always call path root(=1) -> u while(head[u] != head[v]){ seg.update(1,1,n,pos[head[u]],pos[u], val); u = parentArr[head[u]]; } if(pos[v] <= pos[u]) seg.update(1,1,n,pos[v],pos[u], val); else seg.update(1,1,n,pos[u],pos[v], val); } void tinh(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n>>Q; for(int i=1;i<=n;i++){ adj[i].clear(); deg[i]=0; } for(int i=1;i<=n-1;i++){ int u,v; cin>>u>>v; adj[u].pu(v); adj[v].pu(u); deg[u]++; deg[v]++; } // pick root as any non-leaf (or 1 if ok) int root = 1; for(int i=1;i<=n;i++) if(deg[i]>1){ root=i; break; } if(root==0) root=1; depthArr[root]=0; dfs1(root,0); curPos=0; dfs_hld(root,root); // build segtree on positions 1..n seg.init(n); // baseVal already filled at pos // baseSum = sum_{edges} orig_subtree_leaves; note pos[root] corresponds to root node; its baseVal = subLeaf[root] (which equals total leaves) but we should exclude it in sums because it's not an edge. baseSum = 0; for(int i=1;i<=n;i++){ // baseVal[pos[i]] already set } // We will keep pos[root] as well; but it's safe since edges count = n (including root position), root position value = total leaves; However we must exclude it from final sum and from counts. // So easiest: set baseVal[pos[root]] = 0 to exclude root's contribution. baseVal[pos[root]] = 0; // compute baseSum as sum baseVal baseSum = 0; for(int i=1;i<=n;i++) baseSum += baseVal[i]; seg.build(1,1,n); // store original leaf flag for(int i=1;i<=n;i++) origLeaf[i] = (deg[i]==1 ? 1 : 0); int origLeavesTotal = 0; for(int i=1;i<=n;i++) origLeavesTotal += origLeaf[i]; // process Q queries // Note: total number of attachments across all queries <= 1e5 per constraints while(Q--){ int D; cin>>D; vector<int> a(D); for(int i=0;i<D;i++) cin>>a[i]; if(D==0){ // no additions: answer depends only on origLeavesTotal parity and original base if((origLeavesTotal % 2)==1){ cout<<-1<<"\n"; } else { // L = origLeavesTotal ll L = origLeavesTotal; ll T = L/2; // query number > T and sum auto pr = seg.queryGreater(1,1,n,T); ll b = pr.first; ll sum_big = pr.second; // S = current sum of t_i = baseSum (no adds) ll S = baseSum; ll ans = S + b * L - 2 * sum_big; cout<<ans<<"\n"; } continue; } // build count map per node for attachments in this query unordered_map<int,int> cnt; cnt.reserve(D*2); for(int x: a) cnt[x]++; // compute lost = number of distinct aj that were original leaf int lost=0; for(auto &kv: cnt){ int node = kv.first; if(origLeaf[node]) lost++; } ll L = (ll)origLeavesTotal + (ll)D - (ll)lost; if(L % 2 == 1){ cout<<-1<<"\n"; continue; } // prepare net_add per distinct node = cnt[node] - (origLeaf[node]?1:0) // apply updates: for each node v, add net_add[v] on path root->v vector<pair<int,int>> changed; changed.reserve(cnt.size()); ll addDepthSum = 0; // sum net_add[v] * depth[v] for(auto &kv: cnt){ int v = kv.first; int c = kv.second; int net = c - (origLeaf[v] ? 1 : 0); if(net==0) continue; // update path root->v by +net path_update(v, root, net); changed.emplace_back(v, net); addDepthSum += (ll)net * (ll)depthArr[v]; } // Now compute S, b, sum_big ll S = baseSum + addDepthSum; ll T = L/2; auto pr = seg.queryGreater(1,1,n,T); ll b = pr.first; ll sum_big = pr.second; ll ans = S + b * L - 2 * sum_big; cout<<ans<<"\n"; // revert updates for(auto &kv: changed){ int v = kv.first; int net = kv.second; path_update(v, root, -net); } } } int main(){ ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); tinh(); return 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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...