2019.09.15【NOIP提高组】模拟 A 组(双指针、双头栈、重构树、树链剖分)

T1:显然拆位处理。

从高到低每一位做一次并查集,如果1和n联通那么就加上ans。

T2:这题的套路较多。

首先要用到一个双指针的套路:用l、r表示当前的区间。每次把r往后移,知道区间合法为止,然后再把l往后移,知道区间不合法为止,每次区间合法时就用r-l+1来更新ans。现在这样出来的答案一定是对的。

那么现在问题就变成了如何判断一个区间是否合法。这里要用到双头栈(我也不知道是不是这样叫)。其实就是有f和g两个dp数组,每次从后面加数时就加到g里,从前面删数时就从f中删。每当f被删空时就把g里的元素全部移到f里。易证这样做的复杂的树O(nw)的。

注意:每次加g、删f和移g时都要注意一下顺序,不要搞错了。

总结:双指针套路可以用于从一个大区间中找出一个满足条件的最…的小区间的题目。通常配合着双头栈使用。

T3:这题的代码超长。

首先我们要建出克鲁斯卡尔重构树(具体见“克鲁斯卡尔重构树”)。建法就是a[new]=a[x]+a[y],b[new]=min(b[x],b[y],l)。

然后我们发现每次修改一个x的val时其实就是修改x到root上所有点的a,然后还要维护一个最大值。那么就可以用树链剖分。

我们把这棵树剖了,然后对于每一条重链都进行分块,每一个块里都维护一个凸壳(类似于斜率优化)。我们考虑如果给一个点x的a加上v,那么它的值就会有a[x]*b[x]变成(a[x]+v)*b[x]=b[x]*v+a[x]*b[x]。然后根据这个推式子,求出单调栈。

接着每次修改的时候对于一个整块的修改,我们就打上一个懒惰标记g,并且维护出当前这个区间的所有a值都加上了g之后的最大值(这个可以在单调栈上二分);对于散块的修改,直接暴力重构就好了。

最后,我们要维护所有块的最大值,这个用set。

最终的时间复杂度是O(m*logn*sqrt(n))的。

总结:我打这题是出现了以下几个错误:

1、数组的下表的意义没有一一对应。这种设计到几个层次的题要注意数组的意义要对应。

2、修改要在找原来的最小值之前。

3、忘记判断斜率为0的情况。以后只要用到斜率,那么就一定要判断斜率为0的情况!!!!!!

最后贴一下代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#define ll long long
#define MAXN 600010
#define MAXM 1200010
using namespace std;

struct map
{
	int x;
	int y;
};
map way[MAXM];
struct map1
{
	int x;
	int y;
	ll l;
};
map1 c[MAXM];
struct heavychain
{
	int x;
	int top;
	int dfn;
};
heavychain d[MAXN];
struct sor
{
	ll b;
	int num;
};
sor e[MAXN];
int first[MAXN],nxt[MAXM],size[MAXN],son[MAXN],top[MAXN],fa[MAXN],n,m,cm,T,x,bz[MAXN];
int inf=2000000000,root,dfn[MAXN],tim,u[MAXN],v[MAXN],len[MAXN],ret[MAXN],f[MAXN],sum[MAXN];
int hson[MAXN],q[MAXN][3],tq;
ll a[MAXN],b[MAXN],k,g[MAXN],val[MAXN],last[MAXN];
multiset<ll>ma;
multiset<ll>::iterator it;
int find(int x)
{
	if(fa[x]!=x)fa[x]=find(fa[x]);
	return fa[x];
}
int add(int x,int y)
{
	m++;way[m].x=x;way[m].y=y;
	m++;way[m].x=y;way[m].y=x;
}
int bfs1()
{
	int i,tf;
	q[1][0]=root;q[1][1]=first[q[1][0]];
	size[root]=1;bz[root]=1;
	tq=1;
	while(tq>=1)
	{
		tf=0;
		while(q[tq][1]>=1&&q[tq][1]<=m)
		{
			i=q[tq][1];
			if(bz[way[i].y]==0)
			{
				tq++;q[tq][0]=way[i].y;q[tq][1]=first[q[tq][0]];
				bz[way[i].y]=1;fa[way[i].y]=q[tq-1][0];size[way[i].y]=1;
				tf=1;break;
			}
			q[tq][1]=nxt[q[tq][1]];
		}
		if(tf==0)
		{
			size[fa[q[tq][0]]]+=size[q[tq][0]];
			if(size[q[tq][0]]>hson[fa[q[tq][0]]])
				{hson[fa[q[tq][0]]]=size[q[tq][0]];son[fa[q[tq][0]]]=q[tq][0];}
			tq--;
		}
	}
}
int bfs2()
{
	int i,tf;
	q[1][0]=root;q[1][1]=first[q[1][0]];q[1][2]=root;tq=1;
	bz[root]=1;top[root]=root;
	tim++;dfn[root]=tim;
	while(tq>=1)
	{
		tf=0;
		if(bz[son[q[tq][0]]]==0)
		{
			tq++;q[tq][0]=son[q[tq-1][0]];q[tq][1]=first[q[tq][0]];q[tq][2]=q[tq-1][2];
			bz[q[tq][0]]=1;top[q[tq][0]]=q[tq][2];
			tim++;dfn[q[tq][0]]=tim;
			tf=1;
		}
		while(q[tq][1]>=1&&q[tq][1]<=m&&tf==0)
		{
			i=q[tq][1];
			if(bz[way[i].y]==0)
			{
				tq++;q[tq][0]=way[i].y;q[tq][1]=first[q[tq][0]];q[tq][2]=q[tq][0];
				bz[q[tq][0]]=1;top[q[tq][0]]=q[tq][2];
				tim++;dfn[q[tq][0]]=tim;
				tf=1;break;
			}
			q[tq][1]=nxt[q[tq][1]];
		}
		if(tf==0)tq--;
	}
}
int game1(const map1 &a,const map1 &b)
{
	if(a.l<b.l)return 1;
	else return 0;
}
//////////////////////////////////////////////////////////////////////////////////////
int game3(const sor &x,const sor &y)
{
	if(x.b<y.b)return 1;
	else return 0;
}
ll quiry(int num)
{
	int i,l,r,mid,ans=-1;
	l=num;r=sum[num]-1;
	while(l<=r)
	{
		mid=(l+r)/2;
		//(a[f[mid]]*b[f[mid]]-a[f[mid+1]]*b[f[mid+1]])/(b[f[mid]]-b[f[mid+1]])<-g[num]
		if((a[d[f[mid]].x]*b[d[f[mid]].x]-a[d[f[mid+1]].x]*b[d[f[mid+1]].x])>
		-g[num]*(b[d[f[mid]].x]-b[d[f[mid+1]].x]))
		{ans=mid;r=mid-1;}
		else l=mid+1;
	}
	if(ans==-1)ans=sum[num];
	return (a[d[f[ans]].x]+g[num])*b[d[f[ans]].x];
}
int pd(int x,int y,int p,int q)
{
	//(a[x]*b[x]-a[y]*b[y])/(b[x]-b[y])>(a[p]*b[p]-a[q]*b[q])/(b[p]-b[q])
	if((a[x]*b[x]-a[y]*b[y])*(b[p]-b[q])>(a[p]*b[p]-a[q]*b[q])*(b[x]-b[y]))return 100;
	else return 50;
}
int build(int l,int r,int type)
{
	int i,j,h;
	ll w=0,v;
	if(type==1)
	{
		for(i=l;i<=r;i++)
			if((a[d[i].x]+g[l])*b[d[i].x]>w)w=(a[d[i].x]+g[l])*b[d[i].x];
		it=ma.find(last[l]);ma.erase(it);
		ma.insert(w);last[l]=w;
	}
	else
	{
		for(i=l;i<=r;i++)
			if(a[d[i].x]*b[d[i].x]>w)w=a[d[i].x]*b[d[i].x];
		ma.insert(w);last[l]=w;
	}
	for(i=l;i<=r;i++)a[d[i].x]+=g[l];
	g[l]=0;
	sum[l]=l-1;
	for(i=l;i<=r;i++)
	{
		j=i;v=a[d[e[j].num].x]*b[d[e[j].num].x];h=j;
		while(j+1<=r&&e[j+1].b==e[j].b)
		{
			j++;
			if(a[d[e[j].num].x]*b[d[e[j].num].x]>v){v=a[d[e[j].num].x]*b[d[e[j].num].x];h=j;}
		}
		while(sum[l]>=l+1&&pd(d[f[sum[l]-1]].x,d[f[sum[l]]].x,d[f[sum[l]]].x,d[e[h].num].x)==50)sum[l]--;
		sum[l]++;f[sum[l]]=e[h].num;
		i=j;
	}
}
int work(int x,int y)
{
	int i,j,block=top[x];
	for(i=ret[x];i<=ret[y];i=i+len[block])
	{
		if(i+len[block]-1<=ret[y])
		{
			it=ma.find(last[i]);ma.erase(it);
			g[i]+=k;last[i]=quiry(i);
			ma.insert(last[i]);
		}
		else
		{
			for(j=i;j<=ret[y];j++)a[d[j].x]=a[d[j].x]+k;
			if(i+len[block]-1<=v[block])build(i,i+len[block]-1,1);
			else build(i,v[block],1);
		}
	}
}
int game2(const heavychain &a,const heavychain &b)
{
	if(a.top<b.top)return 1;
	if(a.top>b.top)return 0;
	if(a.dfn<b.dfn)return 1;
	else return 0;
}
ll read()
{
	ll s=0;
	char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while('0'<=c&&c<='9')s=s*10+c-'0',c=getchar();
	return s;
}
int main()
{
//freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
int i,j,x1,y1;
n=read();T=read();
for(i=1;i<=n;i++)a[i]=read(),val[i]=a[i];
cm=n-1;
for(i=1;i<=cm;i++){c[i].x=read();c[i].y=read();c[i].l=read();}
sort(c+1,c+cm+1,game1);
for(i=1;i<=n;i++)fa[i]=i,b[i]=inf;
for(i=cm;i>=1;i--)
{
	x1=find(c[i].x);y1=find(c[i].y);
	if(x1!=y1)
	{
		n++;fa[n]=n;
		fa[x1]=n;fa[y1]=n;
		a[n]=a[x1]+a[y1];b[n]=min(min(b[x1],b[y1]),c[i].l);
		add(x1,n);add(y1,n);
	}
}
for(i=1;i<=cm+1;i++)b[i]=0;
for(i=m;i>=1;i--)nxt[i]=first[way[i].x],first[way[i].x]=i;
root=find(1);
memset(fa,0,sizeof(fa));
bfs1();
memset(bz,0,sizeof(bz));
bfs2();
for(i=1;i<=n;i++){d[i].x=i;d[i].top=top[i];d[i].dfn=dfn[i];}
sort(d+1,d+n+1,game2);
for(i=1;i<=n;i++)ret[d[i].x]=i;
for(i=1;i<=n;i++)
	if(u[d[i].top]==0)u[d[i].top]=i,v[d[i].top]=i;
	else v[d[i].top]=i;
for(i=1;i<=n;i++)
	if(u[i]!=0)
	{
		len[i]=1;
		while((len[i]+1)*(len[i]+1)/10<v[i]-u[i]+1)len[i]++;
	}
for(i=1;i<=n;i++){e[i].b=b[d[i].x];e[i].num=i;}
for(i=1;i<=n;i++)
	if(u[i]!=0)
		for(j=u[i];j<=v[i];j=j+len[i])
			if(j+len[i]-1<=v[i]){build(j,j+len[i]-1,0);sort(e+j,e+(j+len[i]-1)+1,game3);}
			else {build(j,v[i],0);sort(e+j,e+v[i]+1,game3);}
while(T>=1)
{
	x=read();k=read();
	k=k-val[x];val[x]+=k;
	while(x>=1){work(top[x],x);x=fa[top[x]];}
	it=ma.end();it--;
	printf("%lld\n",*it);
	T--;
}
}
发布了149 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/chiyankuan/article/details/101122260