zoukankan      html  css  js  c++  java
  • P7897 [Ynoi2006] spxmcq 题解

    P7897 [Ynoi2006] spxmcq

    sol

    看完题目我们很容易可以写出一个 \(DP\) ,定义 \(f_i\) 表当前询问的最优解

    \[f_u=a_u+x+\sum max(f_v,0) \]

    其中 \(v\)\(u\) 的儿子

    然后考虑怎么算这个东西

    思考每一个状态的时候肯定是一个森林

    如果 \(x\) 不断递增,那么只可能建边,不可能删边

    所以将问题离线下来,\(x\) 从小到大处理

    于是柿子就变成了

    \(f_u=a_u+x+\sum f_v\)

    于是对于一个 \(x\) 的答案就是当前这个数的(注意不是原树) \(size\times val +sum\)

    所以对于一个节点只需要维护 \(size\)\(sum\) 两个量就可以了

    考虑建边的条件,就是 \(sz \times t+sum ≥0\)

    于是 $t=\lceil \frac{sum}{size} \rceil $

    开一个堆记录一下 \(t\) 的最大值,每次将小于 \(x\) 的边建上

    最后思考建边的时候如何修改 \(size\)\(sum\)

    我们求出 \(dfs\) 序,将树上问题转化到序列问题

    我们发现连接的时候其实是维护向上一串链的 \(sum\)\(size\)

    于是就变成了一个区间改 + 点查的问题,用树状数组可以处理出来

    开两个树状数组,一个 \(sum\) 一个记 \(size\),最后用\(size\times val +sum\)就好了

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn=1e6+5,maxe=2e6+5;
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }
    LL ans[maxn];
    int N,M,a[maxn];
    int lnk[maxn],nxt[maxe],son[maxe],cnt;
    inline void add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
    int vis[maxn],now,f[maxn],fa[maxn];
    struct que{
    	int x;LL y;int id;
    	bool operator <(const que B)const {return y<B.y;}
    }Q[maxn];
    struct Bit{
    	LL c[maxn];
    	void add_x(int x,LL data){
    		for(int i=x;i<=N;i+=i&-i)c[i]+=data;
    	}
    	LL get(int x){
    		LL ret=0;
    		for(int i=x;i;i-=i&-i)ret+=c[i];
    		return ret;
    	}
    }S,T;
    int dfn[maxn],bg[maxn],ed[maxn];
    struct node{
    	LL w;
    	int id;
    	bool operator <(const node B)const {return w>B.w;}
    };
    priority_queue<node> q;
    void dfs(int x){
    	bg[x]=++bg[0];
    	for(int j=lnk[x];j;j=nxt[j]) dfs(son[j]);
    	ed[x]=bg[0];
    	return ;
    }
    LL getsiz(int x){return S.get(ed[x])-S.get(bg[x]-1)+1;}
    LL getval(int x){return T.get(ed[x])-T.get(bg[x]-1)+a[x];}
    LL getans(int x){return getval(x)+getsiz(x)*now;}
    int getfa(int x){
    	return f[x]==x?x:f[x]=getfa(f[x]);
    }
    void get(int x){
    	vis[x]=1;f[x]=fa[x];LL s=getsiz(x),t=getval(x);
    	int fx=getfa(x);if(fa[fx]) S.add_x(bg[fa[fx]],-s),T.add_x(bg[fa[fx]],-t);
    	if(fa[x]) S.add_x(bg[fa[x]],s),T.add_x(bg[fa[x]],t);
    	if(!fx)return ;
    	s=getans(fx);
    	if(s>0)return get(fx);q.push((node){now+(-s-1)/getsiz(fx)+1,fx});
    	return ;
    }
    int main(){
    	freopen("D.in","r",stdin);
    	freopen("D.out","w",stdout);
    	N=read();M=read();
    	for(int i=2;i<=N;i++) add_e(fa[i]=read(),i);
    	for(int i=1;i<=N;i++) a[i]=read(),f[i]=i;
    	for(int i=1;i<=M;i++) Q[i].x=read(),Q[i].y=read(),Q[i].id=i;
    	dfs(1);sort(Q+1,Q+1+M);
    	for(int i=1;i<=N;i++) q.push((node){-a[i],i});
    	for(int i=1;i<=M;i++){
    		now=Q[i].y;
    		while(!q.empty()){
    			node Top=q.top();
    			if(Top.w>now)break;
    			q.pop();
    			if(!vis[Top.id])get(Top.id);
    		}
    		ans[Q[i].id]=getans(Q[i].x);
    	}
    	for(int i=1;i<=M;i++)
    		printf("%lld\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    xmlTextTextReaderNodeType来读取XML元素的类型
    [转]关于两个坐标点的距离的计算问题
    Incorrect decrement of the reference count of an object that is not owned at this point by the caller1
    让ipad时时显示内存剩余量
    【转】苹果开发者账号注册流程
    自定义百度地图气泡
    [转] iOS 常用数学函数
    [转]JDK环境变量的配置
    纬度在换算距离上一度等于多少公里?
    [转]UIDevice uniqueGlobalDeviceIdentifier(百度地图API的那些事)
  • 原文地址:https://www.cnblogs.com/martian148/p/15538585.html
Copyright © 2011-2022 走看看