其他分享
首页 > 其他分享> > CF464E The Classic Problem(线段树 最短路)

CF464E The Classic Problem(线段树 最短路)

作者:互联网

CF464E The Classic Problem

\(\bigstar\texttt{Hint}\):发现没有什么好的突破口?为什么不想想怎样才能实现题目中 \(2^x\) 的加减法呢?

可见每次加减法,我们要做的是将添加的 \(1\) 和右边的连续的 \(1\) 合并为一整段,可以用线段树 \(\mathcal{O(\log n)}\) 实现。

怎样比较大小呢?考虑如何找到两个串第一个不同的位置,则我们需要的就是二分区间、比较这两段区间是否相同。用一个 Hash 即可。

然后就成为了屎题

#define Maxn 100005
#define Maxm 1800005
#define mod 1000000007
int n,m,s,t,tot,MAX,tp,All;
int uu[Maxn],vv[Maxn],dd[Maxn],Pow2[Maxm];
int hea[Maxn],nex[Maxn<<1],ver[Maxn<<1],edg[Maxn<<1];
int pre[Maxn],sta[Maxn];
bool vis[Maxn];
inline void add(int x,int y,int d)
	{ ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot,edg[tot]=d; }
struct TREE
{
	int Hash,ls,rs,rmost,laz; // pushdown !!!!
	TREE(int H=0,int Ls=0,int Rs=0,int Rmost=-1,int Laz=-1):
		Hash(H),ls(Ls),rs(Rs),rmost(Rmost),laz(Laz){}
	inline void Push(int x,int nl,int nr)
	{
		if(x==0) Hash=0,rmost=nr,laz=x;
		else Hash=(Pow2[nr-nl+1]-1+mod)%mod,rmost=-1,laz=x;
	}
}tree[Maxm<<4];
inline void pushdown(int p,int nl,int nr)
{
	if(tree[p].laz!=-1)
	{
		int mid=(nl+nr)>>1;
		tree[p].ls=++All,tree[tree[p].ls].Push(tree[p].laz,nl,mid);
		tree[p].rs=++All,tree[tree[p].rs].Push(tree[p].laz,mid+1,nr);
		tree[p].laz=-1;
	}
}
inline void pushup(int p,int nl,int nr)
{
	int lson=tree[p].ls,rson=tree[p].rs,mid=(nl+nr)>>1;
	tree[p].Hash=(1ll*tree[lson].Hash*Pow2[nr-mid]%mod+tree[rson].Hash)%mod;
	tree[p].rmost=max(tree[lson].rmost,tree[rson].rmost);
}
bool Comp(int pl,int pr,int nl,int nr)
{
	if(nl==nr) return tree[pl].Hash<tree[pr].Hash;
	pushdown(pl,nl,nr),pushdown(pr,nl,nr);
	int mid=(nl+nr)>>1;
	if(tree[tree[pl].ls].Hash!=tree[tree[pr].ls].Hash)
		return Comp(tree[pl].ls,tree[pr].ls,nl,mid);
	else return Comp(tree[pl].rs,tree[pr].rs,mid+1,nr);
}
int Find(int p,int nl,int nr,int l,int r)
{
	if(nl>=l && nr<=r) return tree[p].rmost;
	pushdown(p,nl,nr);
	int mid=(nl+nr)>>1,ret=-inf;
	if(mid>=l) ret=max(ret,Find(tree[p].ls,nl,mid,l,r));
	if(mid<r) ret=max(ret,Find(tree[p].rs,mid+1,nr,l,r));
	return ret;
}
bool Check0(int p,int nl,int nr,int x)
{
	if(nl==nr) return tree[p].Hash==0;
	pushdown(p,nl,nr);
	int mid=(nl+nr)>>1;
	if(mid>=x) return Check0(tree[p].ls,nl,mid,x);
	return Check0(tree[p].rs,mid+1,nr,x);
}
void change(int pl,int pr,int nl,int nr,int l,int r,int x)
{
	if(nl>=l && nr<=r) { tree[pr].Push(x,nl,nr); return; }
	pushdown(pl,nl,nr);
	tree[pr]=tree[pl];
	int mid=(nl+nr)>>1;
	if(mid>=l)
		tree[pr].ls=++All,tree[All]=tree[tree[pl].ls],
		change(tree[pl].ls,tree[pr].ls,nl,mid,l,r,x);
	if(mid<r)
		tree[pr].rs=++All,tree[All]=tree[tree[pl].rs],
		change(tree[pl].rs,tree[pr].rs,mid+1,nr,l,r,x);
	pushup(pr,nl,nr);
}
struct NODE
{
	int num,dist_rt;
	NODE(int N=0,int D=0):num(N),dist_rt(D){}
	bool friend operator < (NODE x,NODE y)
		{ return Comp(y.dist_rt,x.dist_rt,1,MAX); }
	int friend operator + (NODE p,int x)
	{
		int n2=++All;
		if(Check0(p.dist_rt,1,MAX,x)) change(p.dist_rt,n2,1,MAX,x,x,1);
		else
		{
			int pos=Find(p.dist_rt,1,MAX,1,x),n1=++All;
			change(p.dist_rt,n1,1,MAX,pos+1,x,0);
			change(n1,n2,1,MAX,pos,pos,1);
		}
		return n2;
	}
}ds[Maxn];
inline void Short_path()
{
	priority_queue<NODE> q;
	ds[s]=NODE(s,1);
	for(int i=1;i<=n;i++) if(i!=s) ds[i]=NODE(i,2);
	q.emplace(s,0);
	while(!q.empty())
	{
		NODE cur=q.top(); q.pop();
		int Now=cur.num;
		if(vis[Now]) continue;
		vis[Now]=true;
		for(int i=hea[Now];i;i=nex[i])
		{
			NODE tmp=NODE(ver[i],ds[Now]+edg[i]);
			if(ds[ver[i]]<tmp)
				ds[ver[i]]=tmp,pre[ver[i]]=Now,
				q.push(ds[ver[i]]);
		}
	}
}
int main()
{
	n=rd(),m=rd(),All=2;
	for(int i=1;i<=m;i++) uu[i]=rd(),vv[i]=rd(),dd[i]=rd(),MAX=max(MAX,dd[i]);
	MAX=MAX*log2(n)+1000;
	for(int i=1;i<=m;i++)
		add(uu[i],vv[i],MAX-dd[i]),add(vv[i],uu[i],MAX-dd[i]);
	s=rd(),t=rd(),Pow2[0]=1;
	for(int i=1;i<=MAX;i++) Pow2[i]=Pow2[i-1]*2%mod;
	if(s==t) { printf("0\n1\n%d\n",s); return 0; }
	memset(pre,-1,sizeof(pre));
	tree[1].Push(0,1,MAX);
	tree[2].Push(1,1,MAX);
	Short_path();
	if(pre[t]==-1) printf("-1\n");
	else
	{
		sta[++tp]=t;
		for(int x=pre[t];x!=-1;x=pre[x]) sta[++tp]=x;
		printf("%d\n%d\n",tree[ds[t].dist_rt].Hash,tp);
		for(int i=tp;i>=1;i--) printf("%d ",sta[i]);
		printf("\n");
	}
	return 0;
}

标签:nl,Classic,int,CF464E,tree,mid,ls,Problem,nr
来源: https://www.cnblogs.com/EricQian/p/16585819.html