zoukankan      html  css  js  c++  java
  • uoj#418. 【集训队作业2018】三角形(线段树合并)

    传送门

    好迷啊……膜一下ljz

    考虑每个操作,如果把操作按先后顺序放到序列上的话,操作一就是把(w_i)的石子放到某个节点,那么就是在序列末端加入(w_i),然后根据贪心肯定要把它所有儿子的石子拿走,也就是要减去(sum w_{son})

    那么每个点的答案就是序列的最大前缀

    因为父亲节点的操作一要在儿子之后进行,很麻烦,那么可以每次在自己这里把(w_i)减掉,到父亲的时候再加回去

    ((x,y))为一个二元组,(x)表示当前位置的最大前缀和,(y)表示最小后缀和,然后定义一个运算((ax,by)=(x+max(0,a+y),b+min(0,a+y)),大概能看出是个什么东西,注意这个运算不满足交换律

    然后考虑一下这些二元组在序列中的顺序,如果(x+y<0),那么肯定得放前面,因为可以让之后的前缀和减小。

    那么当(x+y<0)时,按(x)排序,这样能使前缀和不断减小。如果(x+y>0),按(y)排序就好了

    维护二元组的话,用线段树合并,如果当前二元组的(x+y<0)且有比它最大前缀大的二元组,那么就已经是最优的了否则将在它前面的二元组与它合并,合并完后加进线段树里就好了。注意合并完之后节点没了要记得清空

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define int long long
    #define loli 200000000000000
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    void print(R int x){
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    }
    const int N=4e5+5;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    struct node{
    	int mx,mn;
    	node(){}
    	node(R int mx,R int mn):mx(mx),mn(mn){}
    	inline node operator +(const node &b){return node(mx+max(0ll,mn+b.mx),b.mn+min(0ll,mn+b.mx));}
    }tr[N<<5];
    int w[N],rt[N],ans[N],ls[N<<5],rs[N<<5];
    int n,cnt,fa;
    void ins(int &p,int l,int r,node x){
    	if(!p)p=++cnt;if(l==r)return (void)(tr[p]=tr[p]+x);
    	int mid=(l+r)>>1;
    	x.mx<=mid?ins(ls[p],l,mid,x):ins(rs[p],mid+1,r,x);
    	tr[p]=tr[ls[p]]+tr[rs[p]];
    }
    int merge(int x,int y,int l,int r){
    	if(!x||!y)return x|y;if(l==r)return tr[x]=tr[x]+tr[y],x;
    	int mid=(l+r)>>1;
    	ls[x]=merge(ls[x],ls[y],l,mid),rs[x]=merge(rs[x],rs[y],mid+1,r);
    	tr[x]=tr[ls[x]]+tr[rs[x]];
    	return x;
    }
    void update(int &p,int l,int r,node &x,bool &flag){
    	if(!p||flag)return;
    	if(l==r){
    		if(x.mx+x.mn<0&&x.mx<l)return (void)(flag=1);
    		x=x+tr[p],p=0;return;
    	}
    	int mid=(l+r)>>1;
    	update(ls[p],l,mid,x,flag),update(rs[p],mid+1,r,x,flag);
    	if(ls[p]||rs[p])tr[p]=tr[ls[p]]+tr[rs[p]];
    	else p=0;
    }
    void dfs(int u){
    	node res=node(0,-w[u]);
    	go(u){
    		res.mx+=w[v],dfs(v);
    		rt[u]=merge(rt[u],rt[v],0,loli);
    	}
    	node qaq=res;bool flag=0;
    	qaq.mx+=w[u],ans[u]=(qaq+tr[rt[u]]).mx;
    	update(rt[u],0,loli,res,flag),ins(rt[u],0,loli,res);
    }
    signed main(){
    //	freopen("testdata.in","r",stdin);
    	read(),n=read();
    	fp(i,2,n)fa=read(),add(fa,i);
    	fp(i,1,n)w[i]=read();
    	dfs(1);
    	fp(i,1,n)print(ans[i]);
    	return Ot(),0;
    }
    
  • 相关阅读:
    微信公众号对接配置
    ASP.NET MVC5+EF6+EasyUI 后台管理系统(89)-国际化,本地化,多语言应用
    Nacos安装教程
    IDEA 中创建SpringBoot 父子模块
    解决死锁之路(终结篇)
    CentOS安装node和npm
    CentOS安装RabbitMQ
    在LibreOffice中插入代码
    PowerShell查找程序路径
    使用命令行调用控制面板的选项
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10231616.html
Copyright © 2011-2022 走看看