日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P2056-[ZJOI2007]捉迷藏【点分树,堆】

發布時間:2023/12/3 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P2056-[ZJOI2007]捉迷藏【点分树,堆】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P2056


題目大意

nnn個點的一棵樹,開始全是黑點,有操作

  • 取反一個點的顏色
  • 求最遠的黑點之間的距離

  • 解題思路

    根據點分治每個點和分散開來的重心連邊,然后每個點往上只會有logloglog層節點。

    對于每個點分樹上節點我們需要維護最長路和次長路,然后要注意它們不能在同一個點分子樹上。

    只會對于每個點xxx我們需要維護xxx的點分樹子樹中每個點到xxx的父節點的真實距離的堆。然后還有每個點的所有子節點的堆頂元素的堆。還有一個維護每個節點答案的堆。

    時間復雜度O(nlog?n)O(n\log n)O(nlogn)


    codecodecode

    #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<queue> #include<set> #define mp(x,y) make_pair(x,y) using namespace std; const int N=1e5+10,inf=1e9,T=18; struct node{int to,next; }a[N*2]; int read(){int x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; } int n,tot,num,root,q,ls[N],f[N],siz[N],d[N],fa[N]; int dep[N],g[N][T+1];bool v[N],vis[N]; struct heap{priority_queue<int> q1,q2;void insert(int x){q1.push(x);}void erase(int x){q2.push(x);}int top(){while(!q2.empty()&&q1.top()==q2.top())q2.pop(),q1.pop();return q1.top();}int top2(){int w=top();erase(w);int ans=top();insert(w);return ans;}int size(){return q1.size()-q2.size();} }q1[N],q2[N],ans; void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void dfs(int x,int fa){dep[x]=dep[fa]+1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;g[y][0]=x;dfs(y,x);}return; } int LCA(int x,int y){if(dep[x]>dep[y])swap(x,y);for(int i=T;i>=0;i--)if(dep[g[y][i]]>=dep[x])y=g[y][i];if(x==y)return x;for(int i=T;i>=0;i--)if(g[x][i]!=g[y][i])x=g[x][i],y=g[y][i];return g[x][0]; } int Dis(int x,int y) {return dep[x]+dep[y]-dep[LCA(x,y)]*2;} void groot(int x,int fa){siz[x]=1;f[x]=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa||vis[y])continue;groot(y,x);siz[x]+=siz[y];f[x]=max(f[x],siz[y]);}f[x]=max(f[x],num-siz[x]);if(f[x]<f[root])root=x;return; } void calc(int x,int fa,int sav,int root){int dis=Dis(root,x);q1[sav].insert(dis);for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa||vis[y])continue;calc(y,x,sav,root);}return; } int count(int x) {return q2[x].top()+q2[x].top2();} void build(int x){vis[x]=1;q2[x].insert(0);int S=num;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(vis[y])continue;root=0;num=(siz[y]<siz[x])?siz[y]:S-siz[x];groot(y,x);y=root;fa[y]=x;calc(y,x,y,x);q2[x].insert(q1[y].top());build(y);}if(q2[x].size()>1)ans.insert(count(x));return; } int main() {n=read();for(int i=1;i<n;i++){int x=read(),y=read();addl(x,y);addl(y,x);}//讀入dfs(1,1);for(int j=1;j<=T;j++)for(int i=1;i<=n;i++)g[i][j]=g[g[i][j-1]][j-1];//預處理求LCA f[0]=inf;num=n;groot(1,1);build(root);num=n;memset(v,0,sizeof(v));scanf("%d",&q);while(q--){char op[3];int x;scanf("%s",op);if(op[0]=='C'){x=read();if(!v[x]){v[x]=1;num--;if(q2[x].size()>1)ans.erase(count(x));q2[x].erase(0);if(q2[x].size()>1)ans.insert(count(x));for(int y=x;fa[y];y=fa[y]){if(q2[fa[y]].size()>1)ans.erase(count(fa[y]));q2[fa[y]].erase(q1[y].top());q1[y].erase(Dis(x,fa[y]));if(q1[y].size())q2[fa[y]].insert(q1[y].top());if(q2[fa[y]].size()>1)ans.insert(count(fa[y]));}}else{v[x]=0;num++;if(q2[x].size()>1)ans.erase(count(x));q2[x].insert(0);if(q2[x].size()>1)ans.insert(count(x));for(int y=x;fa[y];y=fa[y]){if(q2[fa[y]].size()>1)ans.erase(count(fa[y]));if(q1[y].size())q2[fa[y]].erase(q1[y].top());q1[y].insert(Dis(x,fa[y]));q2[fa[y]].insert(q1[y].top());if(q2[fa[y]].size()>1)ans.insert(count(fa[y]));}}}if(op[0]=='G'){if(num<=1)printf("%d\n",num-1);else printf("%d\n",ans.top());}}return 0; }

    總結

    以上是生活随笔為你收集整理的P2056-[ZJOI2007]捉迷藏【点分树,堆】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。