【DS】P5311 [Ynoi2011] 成都七中

考虑点分树,找到最浅的满足条件的点,那么所有连通块符合条件的一定能以它为根来统计到。

考虑一个点 y 满足能作为颜色集合中(但不一定对答案贡献),显然是 xy 的路径所经过的点都满足那个偏序关系。

转化为二位偏序即可,数颜色 HH 的项链,大致按 r 排序,维护最大的 l 来贡献。

哈哈,我不会二位偏序()

节省空间的话可以在建立点分树时就搞当前重心答案。

#include <bits/stdc++.h> #define pb push_back using namespace std; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } #define inf (int)(2e9) #define N (int)(1e5+5) struct node { int l,r,id; node(int lx,int rx,int idd) { l=lx; r=rx; id=idd; } }; vector<int>g[N]; vector<node>Q[N],q,vec; bool vis[N],used[N]; int n,m,ans[N],pre[N],sum[N],col[N],mi,rt,nwsum,sz[N]; int lowbit(int x) { return x&(-x); } void add(int x,int v) { if(x<=0) return ; while(x<=n) sum[x]+=v,x+=lowbit(x); } int qry(int x) { if(x<=0) return 0; int res=0; while(x) res+=sum[x],x-=lowbit(x); return res; } void fd_rt(int x,int ff) { sz[x]=1; int qwq=0; for(int y:g[x]) { if(vis[y]||y==ff) continue; fd_rt(y,x); sz[x]+=sz[y]; qwq=max(qwq,sz[y]); } qwq=max(qwq,nwsum-sz[x]); if(qwq<mi) mi=qwq,rt=x; } void dfs(int x,int ff,int l,int r) { // printf(": %d %d %d %d\n",x,ff,l,r); vec.pb(node(l,r,col[x])); for(auto qwq:Q[x]) { if(!used[qwq.id]&&qwq.l<=l&&qwq.r>=r) { used[qwq.id]=1; q.pb(node(qwq.l,qwq.r,qwq.id)); } } for(int y:g[x]) { if(vis[y]||y==ff) continue; dfs(y,x,min(l,y),max(r,y)); } } bool cmp(const node &x,const node &y) { return x.r<y.r; } void cal(int x) { vec.clear(); q.clear(); dfs(x,0,x,x); sort(vec.begin(),vec.end(),cmp); sort(q.begin(),q.end(),cmp); for(int i=0,j=0;i<q.size();i++) { while(j<vec.size()&&vec[j].r<=q[i].r) { if(vec[j].l>pre[vec[j].id]) { add(pre[vec[j].id],-1); add(vec[j].l,1); pre[vec[j].id]=vec[j].l; } ++j; } // printf("%d %d %d\n",q[i].id,q[i].l,q[i].r); ans[q[i].id]=qry(q[i].r)-qry(q[i].l-1); } for(int i=0;i<vec.size();i++) { add(pre[vec[i].id],-1); pre[vec[i].id]=0; } } void solve(int x) { vis[x]=1; cal(x); for(int y:g[x]) { if(vis[y]) continue; mi=inf; nwsum=sz[y]; fd_rt(y,0); solve(rt); } } int main() { n=rd(); m=rd(); for(int i=1;i<=n;i++) col[i]=rd(); for(int i=1;i<n;i++) { int x=rd(),y=rd(); g[x].pb(y); g[y].pb(x); } for(int i=1;i<=m;i++) { int x=rd(),y=rd(),z=rd(); Q[z].pb(node(x,y,i)); } mi=inf; rt=0; nwsum=n; fd_rt(1,0); solve(rt); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/15872297.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示