zoukankan      html  css  js  c++  java
  • [bzoj4860] [BeiJing2017]树的难题

    Description

    给你一棵 n 个点的无根树。树上的每条边具有颜色。 一共有 m 种颜色,编号为 1 到 m。第 i 种颜色的权值为

    ci。对于一条树上的简单路径,路径上经过的所有边按顺序组成一个颜色序列,序列可以划分成若干个相同颜色段

    。 定义路径权值为颜色序列上每个同颜色段的颜色权值之和。请你计算,经过边数在 l 到 r 之间的所有简单路

    径中, 路径权值的最大值。

    Input

    第一行, 四个整数 n, m, l, r。

    第二行, n 个整数 c1, c2, ……, cm,由空格隔开。依次表示每个颜色的权值。

    接下来 n-1 行,每行三个整数 u, v, c,表示点 u 和点 v 之间有一条颜色为 c 的边。

    Output

    输出一行, 一个整数, 表示答案。

    Sample Input

    5 3 1 4
    -1 -5 -2
    1 2 1
    1 3 1
    2 4 2
    2 5 3
    

    Sample Output

    -1
    

    Solution

    统计链上信息,上点分治。

    对于当前的分治中心,把边按颜色(sort)一遍,然后开两个线段树,对于颜色相同的边用一颗线段树统计,不同的也开一颗,做完一种颜色就把两颗线段树合并一下,然后清空就好了。

    复杂度(O(nlog^2n)),然后凭借信仰过掉此题(跑的还蛮快的)

    不过正解好像是单调队列,我太弱了不会QAQ

    #include<bits/stdc++.h>
    using namespace std;
    
    inline int max(int x,int y) {return x>y?x:y;}
    #define il inline
    
    il void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    il void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    il void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 6e5+10;
    const int inf = 1e9;
    
    int n,m,l,r,tot,st[maxn],ed[maxn],ls[maxn<<2],rs[maxn<<2],tr[maxn<<2],cnt;
    
    struct edge{
    	int fr,to,w;
    	int operator < (const edge &rhs) const {
    		return fr<rhs.fr||(fr==rhs.fr&&w<rhs.w);
    	}
    }e[maxn<<1];
    
    il void add(int u,int v,int w) {e[++tot]=(edge){u,v,w};}
    il void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
    
    #define mid ((l+r)>>1)
    
    namespace Segment_Tree {
    	void modify(int &p,int l,int r,int x,int v) {
    		if(!p) p=++cnt,ls[p]=rs[p]=0,tr[p]=-inf;
    		else tr[p]=max(tr[p],v);
    		if(l==r) return ;
    		if(x<=mid) modify(ls[p],l,mid,x,v);
    		else modify(rs[p],mid+1,r,x,v);
    	}
    	int query(int p,int l,int r,int x,int y) {
    		if(!p) return -inf;
    		if(x<=l&&r<=y) return tr[p];
    		int ans=-inf;
    		if(x<=mid) ans=max(ans,query(ls[p],l,mid,x,y));
    		if(y>mid) ans=max(ans,query(rs[p],mid+1,r,x,y));
    		return ans;
    	}
    	int merge(int x,int y) {
    		if(!x||!y) return x+y;
    		ls[x]=merge(ls[x],ls[y]);
    		rs[x]=merge(rs[x],rs[y]);
    		tr[x]=max(tr[x],tr[y]);
    		return x;
    	}
    }
    
    #undef mid 
    
    using namespace Segment_Tree;
    
    namespace Tree {
    	int rt,f[maxn],sz[maxn],size,vis[maxn],data_cnt,c[maxn],ans,ss[maxn];
    
    	void get_rt(int x,int fa) {
    		sz[x]=1,f[x]=1;
    		for(int i=st[x];i<=ed[x];i++)
    			if(e[i].to!=fa&&(!vis[e[i].to])) 
    				get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
    		f[x]=max(f[x],size-sz[x]);
    		if(f[rt]>f[x]) rt=x;
    	}
    
    	struct data {int dep,dis;}d[maxn];
    
    	void get_data(int x,int fa,int dep,int col,int sum) {
    		if(dep>r) return ;
    		for(int i=st[x];i<=ed[x];i++) {
    			if(e[i].to==fa||vis[e[i].to]) continue;
    			d[++data_cnt]=(data){dep+1,sum+((col==e[i].w)?0:c[e[i].w])};
    			get_data(e[i].to,x,dep+1,e[i].w,sum+((col==e[i].w)?0:c[e[i].w]));
    		}
    	}
    
    	void solve(int x) {
    		vis[x]=1;int r1=0,r2=cnt=0;
    		for(int i=st[x];i<=ed[x];++i) {
    			if(e[i].w!=e[i-1].w&&i!=st[x]) r1=merge(r1,r2),r2=0;
    			if(vis[e[i].to]) continue;
    			data_cnt=0;
    			d[++data_cnt]=(data){1,c[e[i].w]};
    			get_data(e[i].to,x,1,e[i].w,c[e[i].w]);
    			ss[i]=data_cnt;
    			for(int j=1;j<=data_cnt;++j) {
    				if(d[j].dep>r) continue;
    				if(d[j].dep<r) {
    					ans=max(ans,d[j].dis+query(r2,1,n,max(1,l-d[j].dep),r-d[j].dep)-c[e[i].w]);
    					ans=max(ans,d[j].dis+query(r1,1,n,max(1,l-d[j].dep),r-d[j].dep));
    				}
    				if(d[j].dep>=l) ans=max(ans,d[j].dis);
    			}
    			for(int j=1;j<=data_cnt;++j)
    				if(d[j].dep<r) modify(r2,1,n,d[j].dep,d[j].dis);
    		}
    		for(int i=st[x];i<=ed[x];++i) {
    			if(vis[e[i].to]) continue;
    			rt=0,size=ss[i],get_rt(e[i].to,x);
    			solve(rt);
    		}
    	}
    }
    
    using namespace Tree;
    
    int main() {
    	read(n),read(m),read(l),read(r);ans=-inf;
    	for(int i=1;i<=m;i++) read(c[i]);
    	for(int i=1,x,y,z;i<n;i++) read(x),read(y),read(z),ins(x,y,z);
    	sort(e+1,e+n*2-1);int p=1;
    	for(int i=1;i<=n;i++) {
    		st[i]=p;while(e[p].fr==i&&p<=n*2-2) p++;ed[i]=p-1;
    	}
    	rt=0,f[0]=maxn+1,size=n,get_rt(1,0),solve(rt);write(ans);
    	return 0;
    }
    
  • 相关阅读:
    docker常用命令
    centos7安装docker
    windows程序自启动的几种方法(三)系统配置文件
    判断操作系统的类型
    浏览器插件 Browser Helper Object(BHO) 二
    dbf文件结构
    ICE开发中遇到的问题 (一)
    window程序自启动的几种方法(四)
    使用ICE遇到的编译问题
    浏览器插件 Browser Helper Object(BHO) 一
  • 原文地址:https://www.cnblogs.com/hbyer/p/10189183.html
Copyright © 2011-2022 走看看