题解 星际航道

传送门

  • 关于「平面图动态权最小生成树」:
    令 MST 上的边集为 \(T\),考虑 \(T\) 的补集 \(T'\),计算边数得 \(T'\) 也形成了一棵树
    因为边权和是固定的,而 \(T\) 又是最小生成树,所以 \(T'\) 是对偶图的最大生成树
    那么用两棵 LCT 维护这两棵树,修改边权时若能插入另一棵树,就把那棵树中被删掉的边加到这棵树中即可
    这样可以做到 \(O(n\log n)\)
  • 关于「一般图动态权最小生成树」:
    发现若将边权改小是容易维护的
    那么线段树分治处理改大
    另一种做法参照 [HNOI2010]城市建设
    【水博中】
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 600010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int r, c, q, typ;

namespace task{
	char op[10];
	bool vis[N];
	ll val[N], ans;
	pair<ll, int> pos1[N], pos2[N];
	int **id1, **id2, **down, **right, tot;
	struct min_lct{
		bool rev[N];
		ll maxn[N], val[N];
		int fa[N], maxi[N], id[N], son[N][2];
		#define son(a, b) son[a][b]
		#define loc(a) (son(fa[a], 1)==a)
		#define isrot(a) (son(fa[a], 0)!=a&&son(fa[a], 1)!=a)
		void pushup(int a) {
			maxn[a]=max(val[a], max(maxn[son(a, 0)], maxn[son(a, 1)]));
			maxi[a]=val[a]==maxn[a]?id[a]:(maxn[son(a, 0)]==maxn[a]?maxi[son(a, 0)]:maxi[son(a, 1)]);
		}
		void spread(int a) {
			if (!rev[a]) return ;
			if (son(a, 0)) swap(son(son(a, 0), 0), son(son(a, 0), 1)), rev[son(a, 0)]^=1;
			if (son(a, 1)) swap(son(son(a, 1), 0), son(son(a, 1), 1)), rev[son(a, 1)]^=1;
			rev[a]=0;
		}
		void ror(int x) {
			int y=fa[x], z=fa[y], k=loc(x);
			if (!isrot(y)) son(z, loc(y))=x; fa[x]=z;
			son(y, k)=son(x, k^1); fa[son(x, k^1)]=y;
			son(x, k^1)=y; fa[y]=x;
			pushup(y); pushup(x);
		}
		void upd(int x) {if (!isrot(x)) upd(fa[x]); spread(x);}
		void splay(int x) {
			upd(x);
			for (int f; f=fa[x],!isrot(x); ror(x))
				if (!isrot(f)) loc(x)^loc(f)?ror(x):ror(f);
		}
		int access(int x) {
			int lst;
			for (lst=0; x; lst=x,x=fa[x])
				splay(x), son(x, 1)=lst, pushup(x);
			return lst;
		}
		void makerot(int x) {x=access(x); swap(son(x, 0), son(x, 1)); rev[x]^=1;}
		int findrot(int x) {
			x=access(x); spread(x);
			while (son(x, 0)) x=son(x, 0), spread(x);
			splay(x);
			return x;
		}
		void split(int x, int y) {makerot(x); access(y); splay(y);}
		void link(int x, int y) {/* cout<<"lct1::link "<<x<<' '<<y<<endl; */ makerot(x); splay(x); fa[x]=y;}
		void cut(int x, int y) {split(x, y); fa[x]=son(y, 0)=0; pushup(y);}
		pair<ll, int> qmax(int x, int y) {split(x, y); return {maxn[y], maxi[y]};}
		void modify(int x, int w) {splay(x); val[x]=w; pushup(x);}
	}lct1;
	struct max_lct{
		bool rev[N];
		ll minn[N], val[N];
		int fa[N], mini[N], id[N], son[N][2];
		#define son(a, b) son[a][b]
		#define loc(a) (son(fa[a], 1)==a)
		#define isrot(a) (son(fa[a], 0)!=a&&son(fa[a], 1)!=a)
		void pushup(int a) {
			minn[a]=min(val[a], min(minn[son(a, 0)], minn[son(a, 1)]));
			mini[a]=val[a]==minn[a]?id[a]:(minn[son(a, 0)]==minn[a]?mini[son(a, 0)]:mini[son(a, 1)]);
			// cout<<"pushup: "<<a<<' ';
			// cout<<"("<<minn[a]<<','<<mini[a]<<")"<<endl;
			// cout<<"son ("<<son(a, 0)<<','<<son(a, 1)<<")"<<endl;
			// cout<<"val: "<<val[a]<<' '<<id[a]<<endl;
		}
		void spread(int a) {
			if (!rev[a]) return ;
			if (son(a, 0)) swap(son(son(a, 0), 0), son(son(a, 0), 1)), rev[son(a, 0)]^=1;
			if (son(a, 1)) swap(son(son(a, 1), 0), son(son(a, 1), 1)), rev[son(a, 1)]^=1;
			rev[a]=0;
		}
		void ror(int x) {
			int y=fa[x], z=fa[y], k=loc(x);
			if (!isrot(y)) son(z, loc(y))=x; fa[x]=z;
			son(y, k)=son(x, k^1); fa[son(x, k^1)]=y;
			son(x, k^1)=y; fa[y]=x;
			pushup(y); pushup(x);
		}
		void upd(int x) {if (!isrot(x)) upd(fa[x]); spread(x);}
		void splay(int x) {
			upd(x);
			for (int f; f=fa[x],!isrot(x); ror(x))
				if (!isrot(f)) loc(x)^loc(f)?ror(x):ror(f);
		}
		int access(int x) {
			int lst;
			for (lst=0; x; lst=x,x=fa[x])
				splay(x), son(x, 1)=lst, pushup(x);
			return lst;
		}
		void makerot(int x) {x=access(x); swap(son(x, 0), son(x, 1)); rev[x]^=1;}
		int findrot(int x) {
			x=access(x); spread(x);
			while (son(x, 0)) x=son(x, 0), spread(x);
			splay(x);
			return x;
		}
		void split(int x, int y) {makerot(x); access(y); splay(y);}
		void link(int x, int y) {/* cout<<"lct2::link "<<x<<' '<<y<<endl; */ makerot(x); splay(x); fa[x]=y;}
		void cut(int x, int y) {split(x, y); fa[x]=son(y, 0)=0; pushup(y);}
		pair<ll, int> qmin(int x, int y) {split(x, y); return {minn[y], mini[y]};}
		void modify(int x, int w) {splay(x); val[x]=w; pushup(x);}
	}lct2;
	inline void decode(char ch, int &x, int &y, int &w, ll lstans) {
		// R is 'r'
		// C is 'c' 
		static int mask = 0xfffff;
		w = (int) ((w ^ lstans) & mask);
		if(ch == '-') x = (x + lstans - 1) % r + 1, y = (y + lstans - 1) % (c - 1) + 1;
		if(ch == '|') x = (x + lstans - 1) % (r - 1) + 1, y = (y + lstans - 1) % c + 1;
	}
	void solve() {
		id1=new int*[r+2]; id2=new int*[r+2]; down=new int*[r+2]; right=new int*[r+2];
		for (int i=0; i<=r+1; ++i) id1[i]=new int[c+2], id2[i]=new int[c+2];
		for (int i=0; i<=r+1; ++i) down[i]=new int[c+2], right[i]=new int[c+2];
		for (int i=1; i<=r; ++i) for (int j=1; j<=c; ++j) lct1.val[id1[i][j]=++tot]=-INF, lct1.val[id1[i][j]]=-INF;
		for (int i=1; i<r; ++i) for (int j=1; j<c; ++j) lct2.val[id2[i][j]=++tot]=INF, lct2.val[id2[i][j]]=INF;
		for (int i=1; i<=r; ++i) for (int j=1; j<=c; ++j) {
			if (i!=r) down[i][j]=++tot, lct1.maxi[tot]=lct2.mini[tot]=tot;
			if (j!=c) right[i][j]=++tot, lct1.maxi[tot]=lct2.mini[tot]=tot;
		}
		lct1.maxn[0]=-INF, lct2.minn[0]=INF;
		lct2.val[++tot]=INF; lct2.minn[tot]=INF;
		for (int i=0; i<=r; ++i) id2[i][0]=id2[i][c]=tot;
		for (int i=0; i<=c; ++i) id2[0][i]=id2[r][i]=tot;
		for (int i=1; i<=r; ++i) for (int j=1; j<=c; ++j) {
			if (i!=r) pos1[down[i][j]]={id1[i][j], id1[i+1][j]}, pos2[down[i][j]]={id2[i][j-1], id2[i][j]};
			if (j!=c) pos1[right[i][j]]={id1[i][j], id1[i][j+1]}, pos2[right[i][j]]={id2[i-1][j], id2[i][j]};
		}
		for (int i=1; i<=tot; ++i) lct1.id[i]=i, lct2.id[i]=i;
		// lct2.link(5, 9); lct2.link(9, 10);
		// pair<int, int> t=lct2.qmin(5, 10);
		// cout<<"qmin: "<<t.fir<<' '<<t.sec<<endl;
		// exit(0);
		for (int i=1; i<r; ++i) for (int j=1; j<=c; ++j) vis[down[i][j]]=1, lct1.link(id1[i][j], down[i][j]), lct1.link(down[i][j], id1[i+1][j]);
		for (int i=1; i<c; ++i) vis[right[1][i]]=1, lct1.link(id1[1][i], right[1][i]), lct1.link(right[1][i], id1[1][i+1]);
		for (int i=2; i<=r; ++i) for (int j=1; j<c; ++j) lct2.link(id2[i-1][j], right[i][j]), lct2.link(right[i][j], id2[i][j]);
		// exit(0);
		for (int i=1,x,y,w,now,lst; i<=q; ++i) {
			// cout<<"i: "<<i<<endl;
			scanf("%s%d%d%d", op, &x, &y, &w);
			if (typ) decode(*op, x, y, w, ans);
			if (*op=='-') {
				// cout<<"case -"<<endl;
				now=right[x][y];
				lst=val[now]; lct1.modify(now, w), lct2.modify(now, w); val[now]=w;
				if (vis[now]) {
					// cout<<"in mst: "<<endl;
					// cout<<id2[x-1][y]<<' '<<id2[x][y]<<endl;
					pair<ll, int> t=lct2.qmin(id2[x-1][y], id2[x][y]);
					// cout<<"t: "<<t.fir<<' '<<t.sec<<endl;
					if (t.fir<val[now]) {
						// cout<<"cause modify"<<endl;
						lct1.cut(id1[x][y], now), lct1.cut(now, id1[x][y+1]);
						lct1.link(pos1[t.sec].fir, t.sec), lct1.link(t.sec, pos1[t.sec].sec);
						// cout<<"pos2: "<<pos2[t.sec].fir<<' '<<t.sec<<' '<<pos2[t.sec].sec<<endl;
						lct2.cut(pos2[t.sec].fir, t.sec), lct2.cut(t.sec, pos2[t.sec].sec);
						lct2.link(id2[x-1][y], now), lct2.link(now, id2[x][y]);
						vis[now]^=1; vis[t.sec]^=1; ans=ans-lst+t.fir;
					}
					else ans=ans-lst+w;
				}
				else {
					// cout<<"out mst"<<endl;
					// cout<<"between: "<<id1[x][y]<<' '<<id1[x][y+1]<<endl;
					pair<ll, int> t=lct1.qmax(id1[x][y], id1[x][y+1]);
					// cout<<"t: "<<t.fir<<' '<<t.sec<<endl;
					if (t.fir>val[now]) {
						// cout<<"cause modify"<<endl;
						lct2.cut(id2[x-1][y], now), lct2.cut(now, id2[x][y]);
						lct2.link(pos2[t.sec].fir, t.sec), lct2.link(t.sec, pos2[t.sec].sec);
						lct1.cut(pos1[t.sec].fir, t.sec), lct1.cut(t.sec, pos1[t.sec].sec);
						lct1.link(id1[x][y], now), lct1.link(now, id1[x][y+1]);
						vis[now]^=1; vis[t.sec]^=1; ans=ans-t.fir+w;
					}
				}
			}
			else {
				// cout<<"case |"<<endl;
				now=down[x][y];
				// cout<<"now: "<<now<<endl;
				lst=val[now]; lct1.modify(now, w), lct2.modify(now, w); val[now]=w;
				if (vis[now]) {
					// cout<<"in mst: "<<endl;
					// cout<<"find: "<<id2[x][y-1]<<' '<<id2[x][y]<<endl;
					pair<ll, int> t=lct2.qmin(id2[x][y-1], id2[x][y]);
					// cout<<"t: "<<t.fir<<' '<<t.sec<<endl;
					if (t.fir<val[now]) {
						// cout<<"cause modify"<<endl;
						lct1.cut(id1[x][y], now), lct1.cut(now, id1[x+1][y]);
						lct1.link(pos1[t.sec].fir, t.sec), lct1.link(t.sec, pos1[t.sec].sec);
						lct2.cut(pos2[t.sec].fir, t.sec), lct2.cut(t.sec, pos2[t.sec].sec);
						lct2.link(id2[x][y-1], now), lct2.link(now, id2[x][y]);
						vis[now]^=1; vis[t.sec]^=1; ans=ans-lst+t.fir;
					}
					else ans=ans-lst+w;
				}
				else {
					// cout<<"out mst"<<endl;
					pair<ll, int> t=lct1.qmax(id1[x][y], id1[x+1][y]);
					if (t.fir>val[now]) {
						// cout<<"cause modify"<<endl;
						lct2.cut(id2[x][y-1], now), lct2.cut(now, id2[x][y]);
						lct2.link(pos2[t.sec].fir, t.sec), lct2.link(t.sec, pos2[t.sec].sec);
						lct1.cut(pos1[t.sec].fir, t.sec), lct1.cut(t.sec, pos1[t.sec].sec);
						lct1.link(id1[x][y], now), lct1.link(now, id1[x+1][y]);
						vis[now]^=1; vis[t.sec]^=1; ans=ans-t.fir+w;
					}
				}
			}
			printf("%lld\n", ans);
		}
	}
}

signed main()
{
	freopen("channel.in", "r", stdin);
	freopen("channel.out", "w", stdout);

	scanf("%d%d%d%d", &typ, &r, &c, &q);
	task::solve();

	return 0;
}
posted @ 2022-04-07 21:19  Administrator-09  阅读(2)  评论(0编辑  收藏  举报