[硫化铂]星际航道

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[硫化铂]星际航道相关的知识,希望对你有一定的参考价值。

星际航道

题目概述


题解

这道题要强制在线求出网格图的最小生成树,看起来很难搞的样子。
如果离线下来的话是可以线段树分治的,但在线就不好弄了。
我们想想在线我们会如何进行边的替换。
如果我们的 w w w是小于这条边原来的 w w w,那是不是这条边就变得更优了。
如果这条边原来就在我们的生成树,那就保持不变嘛,如果不在,我们就看它是否能替换原树上的边。
显然,这条边在树上插上去后会形成一个环,此时我们减去环上的最长边肯定是最优的,所以我们替换掉的肯定是两端点在树上路径中的最长边。
我们将它维护出来与 w w w比大小即可,这东西用 L C T LCT LCT很好维护。

但如果我们的 w w w如果是变大的不就做不了了吗。
没关系,我们这是网格图,我们可以考虑将它转对偶图。
容易发现,我们将网格图的一个生成树去掉后,剩下的边恰好可以在对偶图上形成一个生成树。
这点也非常容易证明,对偶图上的任意一个环必定对应着网格图中两个集合没有联通,反之亦然。
所以我们最后得到的其实是 网格图 中的 最小生成树 + 对偶图 中的 最大生成树
那么我们其实可以维护两棵树,当它变小时就在第一棵树上找到它是不是能替换边以及替换哪条边,当它变大时就在第二棵树上找边,然后再进行删边加边的操作。
这样,我们就做到 O ( log ⁡ n ) O\\left(\\log n\\right) O(logn)维护单次操作了。

时间复杂度 O ( q log ⁡ n ) O\\left(q\\log n\\right) O(qlogn)

源码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast") 
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 100005
#define MAXM 500005
#define MAXQ 200005
#define pb push_back
#define mkpr make_pair
#define fir first 
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
const int INF=0x3f3f3f3f;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f; 

template<typename _T>
void print(_T x)if(x>9)print(x/10);putchar(x%10+'0');
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;return t;
struct edgeint u1,v1,u2,v2,w,col;s[MAXM];
struct mingint ch[2],fa,maxx,mxid,minn,mnid,val,id;bool rev;;
int typ,R,C,q,n1,n2,m,id[MAXN][2];
class LinkCutTree
	private:
		ming tr[MAXM];int sta[MAXM],stak,nn;
		void pushup(int rt)
			tr[rt].maxx=(rt<=nn?-1:tr[rt].val),tr[rt].mxid=tr[rt].id;
			tr[rt].minn=(rt<=nn?INF:tr[rt].val),tr[rt].mnid=tr[rt].id;
			if(tr[rt].ch[0]&&tr[tr[rt].ch[0]].maxx>tr[rt].maxx)
				tr[rt].maxx=tr[tr[rt].ch[0]].maxx,tr[rt].mxid=tr[tr[rt].ch[0]].mxid;
			if(tr[rt].ch[0]&&tr[tr[rt].ch[0]].minn<tr[rt].minn)
				tr[rt].minn=tr[tr[rt].ch[0]].minn,tr[rt].mnid=tr[tr[rt].ch[0]].mnid;
			if(tr[rt].ch[1]&&tr[tr[rt].ch[1]].maxx>tr[rt].maxx)
				tr[rt].maxx=tr[tr[rt].ch[1]].maxx,tr[rt].mxid=tr[tr[rt].ch[1]].mxid;
			if(tr[rt].ch[1]&&tr[tr[rt].ch[1]].minn<tr[rt].minn)
				tr[rt].minn=tr[tr[rt].ch[1]].minn,tr[rt].mnid=tr[tr[rt].ch[1]].mnid;
		
		void Reverse(int rt)swap(tr[rt].ch[0],tr[rt].ch[1]);tr[rt].rev^=1;
		void pushdown(int rt)
			if(tr[rt].rev)
				if(tr[rt].ch[0])Reverse(tr[rt].ch[0]);
				if(tr[rt].ch[1])Reverse(tr[rt].ch[1]);
				tr[rt].rev=0;
			
		
		bool identify(int x)return tr[tr[x].fa].ch[1]==x;
		bool isRoot(int x)return (tr[tr[x].fa].ch[0]^x)&&(tr[tr[x].fa].ch[1]^x);
		void link(int x,int y,int d)tr[x].fa=y;tr[y].ch[d]=x;
		void rotate(int x)
			int y=tr[x].fa,z=tr[y].fa,d1=identify(x),d2=identify(y);
			if(isRoot(y))tr[x].fa=z;else link(x,z,d2);int t=tr[x].ch[d1^1];
			link(t,y,d1);link(y,x,d1^1);pushup(y);pushup(x);
		
		void splay(int x)
			int y=sta[stak=1]=x;while(!isRoot(y))sta[++stak]=y=tr[y].fa;
			while(stak)pushdown(sta[stak--]);
			for(y=tr[x].fa;!isRoot(x);rotate(x),y=tr[x].fa)
				if(!isRoot(y))rotate(identify(x)==identify(y)?y:x);
		
		void access(int x)for(int y=0;x;x=tr[y=x].fa)splay(x),tr[x].ch[1]=y,pushup(x);
		void makeRoot(int x)access(x);splay(x);Reverse(x);
		int findRoot(int x)
			access(x);splay(x);pushdown(x);
			while(tr[x].ch[0])pushdown(x=tr[x].ch[0]);
			splay(x);return x; 
		
	public:
		bool queryLink(int u,int v)makeRoot(u);return findRoot(v)==u;
		int splitMax(int x,int y)makeRoot(x);access(y);splay(y);return tr[y].mxid;
		int splitMin(int x,int y)makeRoot(x);access(y);splay(y);return tr[y].mnid;
		void linkTree(int u,int v)makeRoot(u);if(findRoot(v)^u)tr[u].fa=v;
		void cutTree(int u,int v)if(!queryLink(u,v))return ;tr[v].fa=tr[u].ch[0]=0;pushup(u);
		void modify(int x,int w)tr[x].maxx=tr[x].minn=tr[x].val=w;
		void init(int x)
			for(int i=1;i<=m;i++)tr[i+x].mxid=tr[i+x].mnid=tr[i+x].id=i;
			for(int i=1;i<=x;i++)tr[i].maxx=-1,tr[i].minn=INF;
			nn=x;
		
T1,T2;
int Id1(int x,int y)return (x-1)*C+y;
int Id2(int x,int y)
	if(x<1||y<1||x>=R||y>=C)return (R-1)*(C-1)+1;
	return (x-1)*(C-1)+y;
 
int fa[MAXN];
void makeSet(int x)for(int i=1;i<=x;i++)fa[i]=i;
int findSet(int x)return fa[x]==x?x:fa[x]=findSet(fa[x]);
void unionSet(int a,int b)int u=findSet(a),v=findSet(b);if(u^v)fa[u]=v;
inline void decode(char ch,int &x,int &y,int &w,LL lstans) 
	static int mask=0xfffff;
	w=(int)以上是关于[硫化铂]星际航道的主要内容,如果未能解决你的问题,请参考以下文章

数字航道长江南京航道局开展数字航道数据库查询业务培训

[硫化铂]守序划分问题

[硫化铂]传染

[硫化铂]密码

bzoj1393 旅游航道

[硫化铂]treecnt