Codeforces 600E. Lomset Gelral(树上莫队)
这道题是群友给的,今天无聊就去搞一搞
其实遇到树上的题,我们一般都会把树上的东西给dfs序重新建链再做
然后这道题本身在想怎么用树链剖分维护,老套路打时间戳然后跟着轻重儿子搞两次dfs,类似于滑动窗口那样从一个节点开始dfs,每次先把子树全部装进滑动窗口,然后当我们dfs到下一个节点的时候就把父亲节点扔了然后计算贡献,这样一来就行了
但有个问题,一个树可能有多叉,那么显然任意一节点u的子树未必是儿子v的子树,答案正确性无法保证,而且如果重新装,那就是O(n^2)的,显然不太行
后来发现维护个蛋啊,这个剪掉的过程不就是莫队么?(
然后愉快地ac了,莫队函数基本套用以前的求众数,只不过对于每一cnt i 多维护一下color就行了
代码:
#include <bits/stdc++.h> #include <bits/extc++.h> using namespace std; #define limit (100000 + 5)//防止溢出 #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f #define lowbit(i) i&(-i)//一步两步 #define EPS 1e-9 #define FASTIO ios::sync_with_stdio(false);cin.tie(0); #define ff(a) printf("%d\n",a ); #define pi(a,b) pair<a,b> #define rep(i, a, b) for(ll i = a; i <= b ; ++i) #define per(i, a, b) for(ll i = b ; i >= a ; --i) #define MOD 998244353 #define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next) #define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin) #define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout) #define debug(x) cout<<x<<endl typedef long long ll; typedef unsigned long long ull; char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf; inline ll read(){ #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) ll sign = 1, x = 0;char s = getchar(); while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();} while(s >= '0' && s <= '9'){x = (x << 3) + (x << 1) + s - '0';s = getchar();} return x * sign; #undef getchar }//快读 void print(ll x) { if(x/ 10) print(x / 10); *O++=x % 10+'0'; } void write(ll x, char c = 't') { if(x < 0)putchar('-'),x = -x; print(x); if(!isalpha(c))*O++ = c; fwrite(obuf,O-obuf,1,stdout); O = obuf; } int kase; int n, m, k; int a[limit]; vector<int>g[limit]; int id[limit], eid[limit]; int cnt[limit], sum[limit], ans[limit]; int tot; int fa[limit], depth[limit]; int sizes[limit], son[limit]; void dfs(int u, int pre = 0){ sizes[u] = 1; fa[u] = pre; depth[u] = depth[pre] + 1; for(auto v : g[u]){ if(v == pre)continue; dfs(v,u); sizes[u] += sizes[v]; if (sizes[son[u]] < sizes[v])son[u] = v; } } int ret[limit]; int color[limit]; int back[limit]; void dfs2(int u, int tp){ id[u] = ++tot; color[id[u]] = a[u]; back[id[u]] = u; if(son[u])dfs2(son[u],tp); for(auto v : g[u]){ if(v != son[u] && v != fa[u])dfs2(v,v); } eid[u] = tot;//结尾 } int res = 0; void add(int x){ ans[cnt[color[x]]] -= color[x]; --sum[cnt[color[x]]];//减去多余部分 ++cnt[color[x]];//增加一个count res = max(res, cnt[color[x]]); ++sum[cnt[color[x]]]; ans[cnt[color[x]]] += color[x]; } void del(int x){ ans[cnt[color[x]]] -= color[x]; --sum[cnt[color[x]]];//撤回一个count if(res == cnt[color[x]] and !sum[cnt[color[x]]])--res;//如果没有了那就增加 --cnt[color[x]]; ++sum[cnt[color[x]]]; ans[cnt[color[x]]] += color[x]; } struct node{ int l, r, qid, blo; bool operator<(const node &rhs)const{ if(blo ^ rhs.blo)return l < rhs.l; return blo & 1 ? r < rhs.r : rhs.r < r; } }query[limit]; void solve(){ n = read(); rep(i,1,n){ a[i] = read(); ans[0] += a[i]; } rep(i,1,n-1){ int x,y; x = read(); y = read(); g[x].push_back(y); g[y].push_back(x); } dfs(1,0); dfs2(1,1); int block = int(sqrt(n >= 3 ? n * (2.0 / 3) : n));//分块 rep(i, 1, n){ query[i].l = id[i], query[i].r = eid[i], query[i].qid = i; query[i].blo = query[i].l / block;//分成块 } sort(query + 1, query + 1 + n); int l = 0 , r = 0; rep(i ,1, n){ while(l < query[i].l)del(l++);//缩进 while(l > query[i].l)add(--l); while(r < query[i].r)add(++r); while(r > query[i].r)del(r--); ret[query[i].qid] = ans[res]; } rep(i,1,n){ write(ret[i],' '); } } int32_t main() { #ifdef LOCAL FOPEN; //FOUT; #endif //FASTIO //cin>>kase; //while (kase--) solve(); cerr << "Time elapsed: " << 1.0*clock()/CLOCKS_PER_SEC << "s\n"; return 0; }
天才选手zerol的主页:https://zerol.me/
|
WeepingDemon的个人主页:https://weepingdemon.gitee.io/blog/