6402. 【NOIP2019模拟11.01】Cover(启发式合并)

题目描述

Description

小 A 现在想用 𝑚 条彩灯去装饰家中的走廊,走廊可以视作一个 [1, 𝑛] 的区间,每一条彩灯都能覆盖一个子区间,并且有一个特定的美观程度。
然而为了降低装饰的难度,彩灯能够覆盖的区间两两之间只有包含和不相交的关系,同时为了避免光污染,他希望每个 [1, 𝑛] 中的点至多被 𝑘 条彩灯覆盖。
现在小 A 希望你能告诉他,𝑘 = 1, 2, … , 𝑚 时,选出的彩灯的最大美观程度之和时多少。

Input

第一行两个个整数 𝑛, 𝑚 表示区间的长度与彩灯的数量。
接下来 𝑚 行,每行三个整数 𝑙𝑖 , 𝑟𝑖 , 𝑎𝑖 表示一条彩灯能够覆盖的区间以及它的美观程度。

Output

输出一行 𝑚 个整数,第 𝑖 个数表示 𝑘 = 𝑖 时的最大美观程度。

Sample Input

25 6
1 2 10
2 3 10
1 3 21
3 4 10
4 5 10
3 5 19 

Sample Output

41 80 80 80 80 80

Data Constraint

对于 25% 的数据,𝑚 ≤ 20
对于 45% 的数据,𝑛, 𝑚 ≤ 5000
对于另外 25% 的数据,所有 𝑎𝑖 相同
对于 100% 的数据,1 ≤ 𝑙𝑖 ≤ 𝑟𝑖 ≤ 𝑛, 𝑚 ≤ 300000, 𝑎𝑖 ≤ 10^9

题解

题目中给出的其实是端点,覆盖的是两点中间的区间

用栈处理出区间之间的关系,问题变成给出一棵树,每个点有权值,选若干节点使得任意一点到根的选取节点个数<=k(k=1~m)的最大权值和

n^2dp显然,设f[i][j]表示以i为根的子树中选取节点个数<=j的最大权值和
f[i][j]=min(∑f[son][j],∑f[son][j-1]+a[i])

可以发现f[i][j+1]-f[i][j]的值单调不增

感性证明:

考虑由j的选择方案变为j+1的方案,可以分为删点和加点两步

删点的目的是为了选择其它的某些点,所以其实是在j不变的情况调整点的选择,之后再加新点

若调整的收益>0,那么必然在j的时候就已经调整完了,若<=0则没有必要

如果只考虑加点的情况下增量变大,那么可以把j-1-->j和j-->j+1的新增点交换一下

于是可以set启发式合并维护差分表

具体写法:轻重链剖分,先走重儿子(不用新建set,相当于直接上传),走完后走轻儿子(新建set,走完后合并到重儿子上面)

这样只需要开log n个set,时间为O(n log^2 n)

合并儿子就对应位置相加,+a[i]就把a[i]丢到set里

证明:
设f[i][j+1]-f[i][j]<a[i],设f[i][j]=x,设f[i][j]-->f[i][j+1],f[i][j+1]-->f[i][j+2]...的差值为b[1],b[2]...,那么a[i]>b[1]>=b[2]...

那么原先的序列为x,x+b[1],x+b[1]+b[2]...

dp更新之后为x,x+a[i],x+a[i]+b[1]...

差值为a[i],b[1],b[2]...

可以发现,实际上相当于把后面的差值后移了一位,所以直接把a[i]丢到set里就行了

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <set>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
using namespace std;

struct type{
	int l,r,s;
} A[300001];
int a[300001][2];
int B[16];
int ls[300001];
int d[300001];
int d2[300001]; //father(bfs)/tier(dfs)
int fa[300001];
long long ans[300001];
bool bz[300001];
int size[300001];
int nx[300001];
int mx[300001];
long long b[300001];
int Ls[300001];
bool Bz[300001];
char st[10800001];
char *Ch=st;
char st2[4800001];
multiset<long long,greater<long long> > S[21];
multiset<long long,greater<long long> > :: iterator I;
int n,m,i,j,k,l,len,h,t,Len;

bool cmp(type a,type b)
{
	return a.r<b.r || a.r==b.r && a.l>b.l;
}

void New(int x,int y)
{
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;Ls[x]=len;
}

int get()
{
	int x=0;
	
	while (*Ch<'0' || *Ch>'9') *++Ch;
	while (*Ch>='0' && *Ch<='9') x=x*10+(*Ch-'0'),*++Ch;
	
	return x;
}
void put(long long x)
{
	int len=0;
	
	while (x)
	{
		B[++len]=x%10;
		x/=10;
	}
	while (len)
	st[++Len]=B[len--]+'0';
	st[++Len]=' ';
}

void bfs(int T)
{
	int i;
	
	h=0;t=1;
	d[1]=T;
	size[T]=1;
	
	while (h<t)
	{
		for (i=ls[d[++h]]; i; i=a[i][1])
		{
			++t;
			d[t]=a[i][0];
			d2[t]=d[h];
			size[a[i][0]]=1;
		}
	}
	
	fd(i,t,2)
	{
		size[d2[i]]+=size[d[i]];
		
		if (mx[d2[i]]<size[d[i]])
		mx[d2[i]]=size[d[i]],nx[d2[i]]=d[i];
	}
	fo(i,1,t)
	if (!nx[d[i]])
	nx[d[i]]=-1,Bz[d[i]]=1;
}

void dfs()
{
	int i,j,T;
	
	while (t)
	{
		T=d[t];
		
		if (!Bz[T])
		{
			Bz[T]=1;
			
			++t;
			d[t]=nx[T];
			d2[t]=d2[t-1];
		}
		else
		{
			if (a[Ls[T]][0]==nx[T])
			Ls[T]=a[Ls[T]][1];
			
			if (Ls[T])
			{
				++t;
				d[t]=a[Ls[T]][0];
				d2[t]=d2[t-1]+1;
				
				Ls[T]=a[Ls[T]][1];
			}
			else
			{
				if (t>1 && d2[t-1]!=d2[t])
				{
					S[d2[t]].insert(A[d[t]].s);
					
					j=0;
					while (!S[d2[t]].empty())
					{
						++j;
						I=S[d2[t]].begin();
						b[j]=*I;
						S[d2[t]].erase(I);
						
						I=S[d2[t]-1].begin();
						b[j]+=*I;
						S[d2[t]-1].erase(I);
					}
					while (j)
					S[d2[t]-1].insert(b[j--]);
				}
				else
				S[d2[t]].insert(A[d[t]].s);
				
				--t;
			}
		}
	}
}

int main()
{
	freopen("cover.in","r",stdin);
	freopen("cover.out","w",stdout);
	
	fread(st,1,10800001,stdin);
	
	n=get();m=get();
	fo(i,1,m)
	A[i].l=get(),A[i].r=get(),A[i].s=get(),--A[i].r;
	
	sort(A+1,A+m+1,cmp);
	
	l=0;
	fo(i,1,m)
	{
		while (l && A[i].l<=A[d[l]].l)
		fa[d[l--]]=i;
		d[++l]=i;
	}
	
	fo(i,1,m)
	if (fa[i])
	New(fa[i],i),bz[fa[i]]=1;
	
	fo(i,1,m)
	if (!fa[i])
	{
		bfs(i);
		
		t=1;
		d[1]=i;
		d2[1]=1;
		dfs();
		
		j=0;
		while (!S[1].empty())
		{
			I=S[1].begin();
			ans[++j]+=*I;
			
			S[1].erase(I);
		}
	}
	
	Len=-1;
	fo(i,1,m)
	{
		ans[i]+=ans[i-1];
		put(ans[i]);
	}
	st[++Len]='\n';
	
	fwrite(st,1,Len,stdout);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}
posted @ 2019-11-07 19:57  gmh77  阅读(520)  评论(0编辑  收藏  举报