zoukankan      html  css  js  c++  java
  • CF643D Bearish Fanpages 题解

    Codeforces
    Luogu

    Description.

    有一棵奇环内向数,第 \(i\) 个点指向 \(f_i\)
    每个点有一个权值 \(t_i\)\(\deg_x\) 表示的是它父亲和儿子总数。
    \(x\) 个点的价值是 \(\left\lceil\frac{t_x}{\deg_x+1}\right\rceil+\sum_{f_x=y\lor f_y=x}\left\lfloor\frac{t_y}{\deg_y+1}\right\rfloor\)
    你需要维护它,支持

    • 改变一个点的父亲,即 \(f_x\rightarrow y\)
    • 计算第 \(i\) 个点的价值
    • 计算当前所有点的最大价值和最小价值

    Solution.

    发现修改会影响它父亲和它父亲周围的所有点,很难处理。
    想到了根号分治,按照 \(\deg\) 分治,但是不够优秀。

    经典套路,我们在一个点父亲处维护它的权值。
    每次单独算它父亲对它贡献权值。
    这样每个点改变会只会影响它在它父亲、它父亲在它父亲父亲、它父亲在它父亲的父亲的父亲的值。
    \(O(1)\) 个数,可以直接用 multiset 暴搞。

    至于操作 3,我们再维护两个 multiset 表示每个 multiset 的最大值和最小值。
    每次单点修改即可。
    总复杂度 \(O(n\log n)\)

    Coding.

    点击查看代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=100005;ll t[N],vl[N];char vs[N];
    multiset<ll>st[N],sx,sn;int f[N],n,Q,dg[N];
    inline void del(int x)
    {
    	if(vs[x]||st[x].empty()) return;else vs[x]=1;
    	sx.erase(sx.find(*--st[x].end()+t[x]/(dg[x]+1)));
    	sn.erase(sn.find(*st[x].begin()+t[x]/(dg[x]+1)));
    }
    inline void add(int x)
    {
    	if(!vs[x]||st[x].empty()) return;else vs[x]=0;
    	sx.insert(*--st[x].end()+t[x]/(dg[x]+1));
    	sn.insert(*st[x].begin()+t[x]/(dg[x]+1));
    }
    inline void work(int u,int y)
    {
    	int x=f[u],fx=f[x],ffx=f[fx],fy=f[y],ffy=f[fy];
    	del(x),del(fx),del(ffx),del(y),del(fy),del(ffy);
    	st[x].erase(st[x].find(vl[u]));
    	st[fx].erase(st[fx].find(vl[x]));//x 少了个儿子,度减少
    	vl[x]-=t[u]/(dg[u]+1);
    	vl[x]-=t[x]-t[x]/(dg[x]+1)*dg[x];
    	vl[x]+=t[x]-t[x]/dg[x]*(dg[x]-1);
    	st[fx].insert(vl[x]);
    	st[ffx].erase(st[ffx].find(vl[fx]));//fx 儿子贡献减少
    	vl[fx]-=t[x]/(dg[x]+1),vl[fx]+=t[x]/dg[x];
    	st[ffx].insert(vl[fx]);
    	dg[x]--,dg[y]++,f[u]=y,st[y].insert(vl[u]);//------------
    	st[fy].erase(st[fy].find(vl[y]));
    	vl[y]+=t[u]/(dg[u]+1);
    	vl[y]+=t[y]-t[y]/(dg[y]+1)*dg[y];
    	vl[y]-=t[y]-t[y]/dg[y]*(dg[y]-1);
    	st[fy].insert(vl[y]);
    	st[ffy].erase(st[ffy].find(vl[fy]));
    	vl[fy]+=t[y]/(dg[y]+1),vl[fy]-=t[y]/dg[y];
    	st[ffy].insert(vl[fy]);
    	add(x),add(fx),add(ffx),add(y),add(fy),add(ffy);
    }
    int main()
    {
    	read(n,Q);for(int i=1;i<=n;i++) read(t[i]),dg[i]=1;
    	for(int i=1;i<=n;i++) read(f[i]),dg[f[i]]++;
    	for(int i=1;i<=n;i++) vl[i]+=t[i]-t[i]/(dg[i]+1)*dg[i];
    	for(int i=1;i<=n;i++) vl[f[i]]+=t[i]/(dg[i]+1);
    	for(int i=1;i<=n;i++) st[f[i]].insert(vl[i]);
    	for(int i=1;i<=n;i++) vs[i]=1,add(i);
    	for(int i=1,fg,x,y;i<=Q;i++)
    	{
    		read(fg);if(fg==1) read(x,y),work(x,y);
    		else if(fg==3) printf("%lld %lld\n",*sn.begin(),*--sx.end());
    		else read(x),printf("%lld\n",vl[x]+t[f[x]]/(dg[f[x]]+1));
    		//printf("?? %lld ; %lld : %lld\n",vl[4],t[f[4]],t[f[4]]/(dg[f[4]]+1));
    	}return 0;
    }
    
  • 相关阅读:
    js学习笔记
    Bootstrap学习笔记
    css学习任务二:切图写代码
    九宫格改进
    js学习笔记
    XHTML复习笔记
    html基础知识复习笔记
    css学习任务一:绘制九宫格
    如何不使用第三个变量来交换两个数的值
    算术右移与逻辑右移
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15386071.html
Copyright © 2011-2022 走看看