zoukankan      html  css  js  c++  java
  • 【洛谷P4319】变化的道路

    题目

    题目链接:https://www.luogu.com.cn/problem/P4319
    小 w 和小 c 在 H 国,近年来,随着 H 国的发展,H 国的道路也在不断变化着。
    根据 H 国的道路法,H 国道路都有一个值 (w),表示如果小 w 和小 c 通过这条道路,那么他们的 L 值会减少 (w),但是如果小 w 和小 c 在之前已经经过了这条路,那么他们的 L 值不会减少。
    H 国有 (N) 个国家,最开始 H 国有 (n-1) 条道路,这 (n-1) 条道路刚好构成一棵树。
    小 w 将和小 c 从 H 国的城市 1 出发,游览 H 国的所有城市,总共游览 32766 天,对于每一天,他们都希望游览结束后 L 值还是一个正数,那么他们出发时 L 值至少为多少。
    H 国的所有边都是无向边,没有一条道路连接相同的一个城市。
    (nleq 50000)

    思路

    就是给出一棵树,再给出若干条边,且后面给的每一条边只有在时间在区间 ([l,r]) 内时才可以走。求每一天的最小生成树 (+1)
    有区间的限制并不是很好搞,所以考虑离线下来。
    还是没什么想法,看题解。线段树分治 + LCT。mlgb 板子题。果然太菜了。
    把每一个询问覆盖到线段树的 (O(log 32766)) 区间上,然后 LCT 维护最小生成树即可。回溯时 cut 一下就好了。
    时间复杂度 (O(mlog mlog n))。其中 (m=32766)

    代码

    喜提最劣解。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=200010,M=32766;
    int n,m,U[N],V[N];
    ll ans;
    
    struct node
    {
    	int x,y;
    };
    
    struct LCT
    {
    	#define lc ch[x][0]
    	#define rc ch[x][1]
    	int val[N],maxv[N],ch[N][2],fa[N];
    	bool rev[N];
    	
    	bool pos(int x) { return x==ch[fa[x]][1]; }
    	bool notrt(int x) { return x==ch[fa[x]][0] || x==ch[fa[x]][1]; }
    	
    	void pushup(int x)
    	{
    		int v1=val[x],v2=val[maxv[lc]],v3=val[maxv[rc]];
    		if (v1>=v2 && v1>=v3) maxv[x]=x;
    		if (lc && v2>=v1 && v2>=v3) maxv[x]=maxv[lc];
    		if (rc && v3>=v1 && v3>=v2) maxv[x]=maxv[rc];
    	}
    	
    	void pushdown(int x)
    	{
    		if (rev[x])
    		{
    			swap(ch[lc][0],ch[lc][1]); rev[lc]^=1;
    			swap(ch[rc][0],ch[rc][1]); rev[rc]^=1;
    			rev[x]=0;
    		}
    	}
    		
    	void rotate(int x)
    	{
    		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
    		if (notrt(y)) ch[z][pos(y)]=x; ch[x][k^1]=y; ch[y][k]=c;
    		if (c) fa[c]=y; fa[y]=x; fa[x]=z;
    		pushup(y); pushup(x);
    	}
    	
    	void splay(int x)
    	{
    		stack<int> st; st.push(x);
    		for (int i=x;notrt(i);i=fa[i]) st.push(fa[i]);
    		for (;st.size();st.pop()) pushdown(st.top());
    		for (;notrt(x);rotate(x))
    		{
    			int y=fa[x];
    			if (notrt(y)) rotate(pos(x)==pos(y)?y:x);
    		}
    	}
    	
    	void access(int x)
    	{
    		for (int y=0;x;y=x,x=fa[x])
    		{
    			splay(x); ch[x][1]=y;
    			pushup(x);
    		}
    	}
    	
    	void makert(int x)
    	{
    		access(x); splay(x);
    		swap(lc,rc); rev[x]^=1;
    	}
    	
    	void link(int x,int y)
    	{
    		makert(x); access(y); splay(y);
    		fa[x]=y; access(x);
    	}
    	
    	void cut(int x,int y)
    	{
    		makert(x); access(y); splay(x);
    		ch[x][1]=fa[y]=0;
    		pushup(x);
    	}
    	#undef lc
    	#undef rc
    }lct;
    
    struct SegTree
    {
    	vector<node> e[N];
    	stack<node> st;
    	
    	void update(int x,int l,int r,int ql,int qr,node v)
    	{
    		if (ql<=l && qr>=r)
    			return (void)e[x].push_back(v);
    		int mid=(l+r)>>1;
    		if (ql<=mid) update(x*2,l,mid,ql,qr,v);
    		if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
    	}
    	
    	void query(int x,int l,int r)
    	{
    		int cnt=st.size();
    		for (int i=0;i<e[x].size();i++)
    		{
    			int w=e[x][i].x,id=e[x][i].y;
    			lct.makert(U[id]); lct.access(V[id]); lct.splay(V[id]);
    			if (lct.val[lct.maxv[V[id]]]>w)
    			{
    				int y=lct.maxv[V[id]];
    				ans=ans-lct.val[y]+w;
    				lct.cut(y,U[y]); lct.cut(y,V[y]);
    				lct.link(id,U[id]); lct.link(id,V[id]);
    				st.push((node){y,id});
    			}
    		}
    		if (l==r) cout<<ans+1<<"
    ";
    		else
    		{
    			int mid=(l+r)>>1;
    			query(x*2,l,mid); query(x*2+1,mid+1,r);
    		}
    		for (;st.size()>cnt;st.pop())
    		{
    			int id1=st.top().x,id2=st.top().y;
    			ans=ans-lct.val[id2]+lct.val[id1];
    			lct.cut(id2,U[id2]); lct.cut(id2,V[id2]);
    			lct.link(id1,U[id1]); lct.link(id1,V[id1]);
    		}
    	}
    }seg;
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<N;i++) lct.maxv[i]=i;
    	for (int i=1,x,y;i<n;i++)
    	{
    		scanf("%d%d%d",&x,&y,&lct.val[i+n]);
    		lct.link(x,i+n); lct.link(y,i+n);
    		ans+=lct.val[i+n];
    		U[i+n]=x; V[i+n]=y;
    	}
    	scanf("%d",&m);
    	for (int i=1;i<=m;i++)
    	{
    		int u,v,l,r,w;
    		scanf("%d%d%d%d%d",&u,&v,&w,&l,&r);
    		lct.val[n*2+i]=w; U[n*2+i]=u; V[n*2+i]=v;
    		seg.update(1,1,M,l,r,(node){w,n*2+i});
    	}
    	seg.query(1,1,M);
    	return 0;
    }
    
  • 相关阅读:
    URL重写,asp.net URL重写,URLRewriter.dll下载,URLRewriter,URLRewriter下载,URL重写学习
    C#制作图像旋转的程序范例

    去掉qq空间不能添加带“=”号的网络音乐地址限制
    《Javascript高级程序设计》读书笔记(二)
    NExcelAPI使用测试
    常用的开源组件
    [转]编程的首要原则(s)是什么?
    《Javascript高级程序设计》读书笔记(一)
    [转]SQL错误处理的脆弱性演示
  • 原文地址:https://www.cnblogs.com/stoorz/p/14866166.html
Copyright © 2011-2022 走看看