• 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;
    }
    
  • 相关阅读:
    The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases.
    线程安全思考
    微服务网关哪家强?一文看懂Zuul, Nginx, Spring Cloud, Linkerd性能差异
    从构建分布式秒杀系统聊聊分布式锁
    基于Redis实现延时队列服务
    Redis分布式锁的正确实现方式
    探究 Redis 4 的 stream 类型
    JAVA 异常分类与理解
    缓存穿透,缓存击穿,缓存雪崩解决方案分析
    分布式之数据库和缓存双写一致性方案解析(一)
  • 原文地址:https://www.cnblogs.com/EricQian/p/16585819.html
Copyright © 2020-2023  润新知