春節十二響(樹剖)

 正解應該是啓發式合併

#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 200000+10;
#define inf 1000000007
int w[maxn],an[maxn];
int N, Q;
ll ans;

struct
{
    int to,next,w;    
}e[maxn<<2];

int head[maxn<<1],edgeNum;

struct
{
	int u,v;
}edge[maxn<<1];

void add(int u,int v)
{
    e[edgeNum].next = head[u];
    e[edgeNum].to = v;
   // e[edgeNum].w=w;
    head[u] = edgeNum++;
}

/*-------------------------樹剖------------------------------*/
int deep[maxn],fa[maxn],siz[maxn],son[maxn];
void dfs1(int u,int pre,int d)
{
    deep[u] = d;
    //fa[u] = pre;
    siz[u] = 1;
    son[u] = 0;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if(v!=pre)
        {
            dfs1(v,u,d+1);
            siz[u] += siz[v];
            if(siz[v]>siz[son[u]])
                son[u] = v;
        }
    }
}

int top[maxn],id[maxn],rk[maxn],cnt;

void dfs2(int u,int t)
{
    top[u] = t;
    id[u] = ++cnt;
    rk[cnt] = u;
    if(!son[u]) return;

    dfs2(son[u],t);

    for(int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if(v!=son[u])
            dfs2(v,v);
    }
}
/*-------------------------樹剖------------------------------*/

/*-------------------------線段樹------------------------------*/
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
	ll sum[maxn<<2];
	int maxid[maxn<<2];
ll lazy[maxn<<2];
void pushup(int rt)
{
	int ls=rt<<1,rs=ls|1;
    //sum[rt] = (sum[rt<<1] + sum[rt<<1|1]);
    sum[rt]=max(sum[ls],sum[rs]);
    if(sum[ls]>sum[rs])maxid[rt]=maxid[ls];//!
    else maxid[rt]=maxid[rs];
}

void pushdown(int rt,int l,int r)
{
    if(lazy[rt])
    {
        lazy[rt<<1] += ( lazy[rt]);
        lazy[rt<<1|1] += ( lazy[rt]);
        sum[rt<<1] += (lazy[rt] );
        sum[rt<<1|1]+= (lazy[rt] );
        lazy[rt] = 0;
    }
}

//void build(int i,int l,int r)
//{
//	if (l==r) {t[i].sum=w[rk[l]];t[i].maxid=rk[l];return;}
//	int mid=(l+r)>>1,ls=i<<1,rs=ls|1;
//	build(ls,l,mid);build(rs,mid+1,r);
//	pushup(i);
//}


void change(int val,int q,int l,int r,int rt)//單點更新 
{
    if(l==r)
    {
        sum[rt] = val;
        maxid[rt]=rk[l];
        return ;
    }
    int m = l + r >> 1;
    if(q<=m)
        change(val,q,lson);
    else
        change(val,q,rson);
    pushup(rt);
}

void update(int L,int R,int val,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        sum[rt] = (sum[rt]+ val) ;
        lazy[rt] = lazy[rt]+val;
        return ;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m)
        update(L,R,val,lson);
    if(R>m)
        update(L,R,val,rson);
    pushup(rt);
}


/*-------------------------線段樹------------------------------*/

/*-----------------------樹剖加線段樹--------------------------*/
void  Update(int x,int y) {
	while(x){
		 update(id[top[x]],id[x],y,1,N,1);
		 x=fa[top[x]];
	}
}

/*-----------------------樹剖加線段樹--------------------------*/

void init()
{
    memset(head,-1,4*N+4);
    cnt = edgeNum = 0;
}

int u, v, o,z,cur;
int main()
{   
		scanf("%d",&N);
   	    init();
   	    for(int i=1;i<=N;i++)scanf("%d",&w[i]);
   	for(int i=2;i<=N;++i)
	{
		scanf("%d",&fa[i]);
		add(fa[i],i);//邊數*2 
		//add(i,fa[i]);
		
	}
	
	dfs1(1,0,1);
	dfs2(1,1);
	//build(1,1,N);
	for(int i=1;i<=N;i++){
	//	int tmp=deep[edge[i].u] > deep[edge[i].v] ? edge[i].u : edge[i].v;
		change(w[i],id[i],1,N,1);
	}
	while(sum[1]>0){
		int max1=0,k=0;
		while(sum[1]>0){
			//cout<<t[1].sum<<endl;
			int x=maxid[1];
			if(sum[1]>max1)max1=sum[1];
			an[++k]=x;
			update(id[x],id[x]+siz[x]-1,-inf,1,N,1);
			Update(fa[x],-inf);
		}
		ans+=max1;
		for(int i=1;i<=k;i++){
			int x=an[i];
				update(id[x],id[x]+siz[x]-1,inf,1,N,1);
			Update(fa[x],inf);
			
		}
		for(int i=1;i<=k;i++){
			int x=an[i];
			update(id[x],id[x],-inf,1,N,1);
		}
	}
	printf("%lld\n",ans);

	   

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章