树的难题 BJOI2017 点分治 单调队列

P3714 [BJOI2017]树的难题

没时间码 先口胡。

明显有一个n^2的暴力。可以拿到20分。

链的情况也非常容易 一个简单的单调队列 就可以解决 当然可以暴力的采用线段树。
这样可以拿到40分。

对于60分 直接考虑线段树合并 利用线段树维护每种颜色的最大值 由于不考虑边数问题。

对于80分 由于总颜色很少 考虑每个点处开颜色个数颗线段树维护深度。

利用线段树合并再每个颜色单独做 复杂度大概两个log的样子 可以过80

不过以上均为口胡没有实现。

考虑100分 容易发现线段树合并失效了 至少需要线段树套线段树才能同时维护边数和颜色。

考虑上点分治来维护边数这个限制。

对于一个重心x 我们将所有的链抽出来进行两条链之间的合并。

分为两种同颜色的合并 不同颜色的合并。发现同时做非常难以处理。

但是我们调换顺序将同颜色的放一块处理 处理时使用单调队列维护即可。

仔细思考单调队列每次都扫一遍复杂度显然不对 我们对于不同颜色的集合 由最深的点由小到大来进入单调队列 这样复杂度才正确。

上述做法可以利用bfs+基数排序进行 不过这个是带log的基数排序在这个地方是带log的 这也就意味着直接sort更优越。尽管前者常数可能会更小。

对于同种颜色 不能按照上述做法 需要再次排序 逐个进行dfs,总之开两个单调队列复杂度还带log.

不妨直接上线段树 简单粗暴 降低代码细节难度。

犯了好多错误:1 q[++top]=mk(e[i],top); 这个写法是未定义的不同的编译器下结果不同。
2 深度没有考虑清楚 在线段树上修改和收集答案的时候都出现了错误。
3 当前节点的贡献没有考虑清楚不是前继节点而是父亲。

复杂度 nlog^2n

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-10
#define sq sqrt
#define a(x) t[x].a
#define sum(x) t[x].sum
#define b(x) t[x].b
#define F first
#define S second
using namespace std;
char *fs,*ft,buf[1<<15];
inline char gc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    return x*f;
}
const int MAXN=200010;
int n,m,L1,R1,len,rt,sum,ans=-INF;
int c[MAXN],son[MAXN],v[MAXN],sz[MAXN];
int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1],e[MAXN<<1];
inline void add(int x,int y,int z)
{
	ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
	ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=z;
}
inline void get_root(int x,int fa)
{
	sz[x]=1;son[x]=0;
	go(x)
	{
		//if(tn==0)cout<<"ww"<<endl;
		if(tn==fa)continue;
		if(v[tn])continue;
		get_root(tn,x);
		sz[x]+=sz[tn];
		son[x]=max(son[x],sz[tn]);
	}
	son[x]=max(son[x],sum-sz[x]);
	if(son[x]<son[rt])rt=x;
}
vector<pair<int,int>>g[MAXN];
int top,w1,w[MAXN];
pair<int,int>q[MAXN];
struct jl
{
	int sum[MAXN<<2];
	int tag[MAXN<<2];
	inline void cs()
	{
		tag[1]=1;
		sum[1]=-INF;
		return;
	}
	inline void pushdown(int p)
	{
		sum[p<<1]=sum[p<<1|1]=-INF;
		tag[p<<1]=tag[p<<1|1]=1;
		tag[p]=0;
	}
	inline void change(int p,int l,int r,int x,int w)
	{
		if(l==r){sum[p]=max(sum[p],w);return;}
		int mid=(l+r)>>1;
		if(tag[p])pushdown(p);
		if(x<=mid)change(p<<1,l,mid,x,w);
		if(x>mid)change(p<<1|1,mid+1,r,x,w);
		sum[p]=max(sum[p<<1],sum[p<<1|1]);
	}
	inline int ask(int p,int l,int r,int L,int R)
	{
		if(sum[p]==-INF)return -INF;
		if(L<=l&&R>=r)return sum[p];
		int mid=(l+r)>>1,mx1=-INF,mx2=-INF;
		if(tag[p])pushdown(p);
		if(L<=mid)mx1=ask(p<<1,l,mid,L,R);
		if(R>mid)mx2=ask(p<<1|1,mid+1,r,L,R);
		return max(mx1,mx2);
	}
}t1,t2;
inline void dfs(int x,int fa,int col,int dis)
{
	go(x)
	{
		if(v[tn])continue;
		if(tn==fa)continue;
		if(col!=e[i])g[top].push_back(mk(w[tn]=w[x]+c[e[i]],dis+1));
		else g[top].push_back(mk(w[tn]=w[x],dis+1));
		dfs(tn,x,e[i],dis+1);
	}
}
inline void solve(int x)
{
	
	if(sz[x]==1)return;
	v[x]=1;t1.cs();t2.cs();
	go(x)
	{
		if(v[tn])continue;
		if(sz[tn]>sz[x])sz[tn]=sum-sz[x];
		++top;q[top]=mk(e[i],top);
		g[top].push_back(mk(c[e[i]],1));
		w[tn]=c[e[i]]; 
		dfs(tn,x,e[i],1);
	}
	sort(q+1,q+1+top);
	int last=0;
	rep(1,top,i)
	{
		if(q[last].F!=q[i].F)
		{
			if(last)
			{
				t2.cs();
				rep(last,i-1,j)
				{
					w1=q[j].S;
					//cout<<g[w1].size()<<endl;
					rep(0,g[w1].size()-1,k)t1.change(1,1,n,g[w1][k].S,g[w1][k].F);
					g[w1].clear();
				}
			}
			last=i;
		}
		rep(0,g[q[i].S].size()-1,j)
		{
			int L=max(L1-g[q[i].S][j].S,0);
			int R=R1-g[q[i].S][j].S;
			if(R<0)continue;
			if(L==0)ans=max(ans,g[q[i].S][j].F),++L;
			if(L>R)continue;
			//if(i==3)cout<<g[q[i].S][j]<<' ';
			ans=max(ans,t1.ask(1,1,n,L,R)+g[q[i].S][j].F);
			ans=max(ans,t2.ask(1,1,n,L,R)-c[q[i].F]+g[q[i].S][j].F);
		}
		w1=q[i].S;
		rep(0,g[w1].size()-1,k)t2.change(1,1,n,g[w1][k].S,g[w1][k].F);
	}
	rep(last,top,i)g[q[i].S].clear();
	top=0;
	go(x)
	{
		if(v[tn])continue;
		sum=sz[tn];rt=0;
		get_root(tn,0);
		solve(rt);
	}
}
int main()
{
	//freopen("1.in","r",stdin);
	
	n=read();m=read();L1=read();R1=read();
	rep(1,m,i)c[i]=read();
	rep(1,n-1,i){int x=read(),y=read(),z=read();add(x,y,z);}
	
	sum=n;son[0]=n+1;
	get_root(1,0);
	
	solve(rt);
	
	printf("%d\n",ans);
	return 0;
}
posted @ 2022-08-30 23:22  chdy  阅读(43)  评论(0编辑  收藏  举报