首页 > 其他分享 >[LOJ3626/QOJ4889] 愚蠢的在线法官

[LOJ3626/QOJ4889] 愚蠢的在线法官

时间:2023-10-19 20:11:20浏览次数:32  
标签:Node LOJ3626 int mk 1ll QOJ4889 愚蠢 adj mod

考虑这个矩阵长啥样,首先显然 \(A\) 不能重复否则答案是 \(0\)(有两行两列相同)。

把 \(A\) 重标号为 DFS 序的顺序,那么行列式的值不改变,因为交换 \(A_i,A_j\) 相当于同时交换两行两列。

考虑把权值 \(v\) 做树上差分,令 \(B_u=v_u-v_{fa(u)}\),那么就等价于对每个 \(i\) 把 \(i\) 子树内的所有点形成的这个矩阵中的每个值都加上 \(B_i\)。那子树的 DFS 序是连续的,所以相当于做一个矩形加。

矩阵上做二维差分不影响行列式,考虑二维差分,那么矩形加就变成了四个单点加。

假设这个对应的 DFS 序区间是 \([l,r]\),那么相当于 M[l][l]++,M[r+1][r+1]++,M[l][r+1]--,M[r+1][l]--,发现这个类似于矩阵树的 Kirchhoff 矩阵,那相当于建一个图出来,然后对每个点连边 \([l,r+1]\),要数生成树个数。

那怎么做呢,发现由于各子树 DFS 序要么包含要么不交,然后你发现任取一个子图如果想同胚于 \(K_4\) 那最后我们发现肯定会出现相交,所以这个是广义串并联图,套广义串并联方法就行了。

时间复杂度 \(O(n\log n)\)。

#include<bits/stdc++.h>

#define ll long long

using namespace std;

inline int read(){
	int x=0,f=1;char c=getchar();
	for(;(c<'0'||c>'9');c=getchar()){if(c=='-')f=-1;}
	for(;(c>='0'&&c<='9');c=getchar())x=x*10+(c&15);
	return x*f;
}

const int mod=998244353;
int ksm(int x,int y,int p=mod){
	int ans=1;
	for(int i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
	return ans%p;
}
int inv(int x,int p=mod){return ksm(x,p-2,p)%p;}
mt19937 rnd(time(0));
int randint(int l,int r){return rnd()%(r-l+1)+l;}
void add(int &x,int v){x+=v;if(x>=mod)x-=mod;}
void Mod(int &x){if(x>=mod)x-=mod;}
int cmod(int x){if(x>=mod)x-=mod;return x;}

const int N=5e5+5;
int n,m;
vector<int>G[N];

struct Node{
	int f,g;
	Node(int F,int G):f(F),g(G){}
	Node(){}
	bool operator<(const Node &rhs)const{
		if(f!=rhs.f)return f<rhs.f;
		return g<rhs.g;
	}
};

Node cmpr(Node wy,Node wz){return Node(1ll*wy.f*wz.f,cmod(1ll*wy.f*wz.g%mod+1ll*wy.g*wz.f%mod));}
Node twist(Node u,Node w){return Node(cmod(1ll*w.f*u.g%mod+1ll*u.f*w.g%mod),1ll*w.g*u.g%mod);}

queue<int>q;
set<pair<int,Node> >adj[N];

#define fi first
#define se second
#define mk make_pair

int dfn[N],dfc=0;
int a[N],val[N],fa[N],sz[N];
bool inq[N];

signed main(void){

#ifdef YUNQIAN
	freopen("in.in","r",stdin);
#endif

	n=read(),m=read();
	for(int i=1;i<=n;i++)val[i]=read();
	for(int i=1;i<=m;i++)a[i]=read();
	for(int i=1;i<=n-1;i++){
		int u=read(),v=read();
		G[u].emplace_back(v),G[v].emplace_back(u);		
	}
	
	function<void(int)>dfs=[&](int u){
		dfn[u]=++dfc,sz[u]=1;
		for(int v:G[u])if(v!=fa[u])fa[v]=u,dfs(v),sz[u]+=sz[v];
		add(val[u],mod-val[fa[u]]);
	};
	dfs(1);
	
	for(int i=1;i<=m;i++)a[i]=dfn[a[i]];sort(a+1,a+m+1);
	
	vector<int>fa(m+2);
	for(int i=1;i<=m+1;i++)fa[i]=i;
	function<int(int)>find=[&](int x){return x==fa[x]?x:fa[x]=find(fa[x]);};
	
	auto adde=[&](int x,int y,Node w){
		if(x==y)return ;fa[find(x)]=find(y);
		set<pair<int,Node> >::iterator t=adj[x].lower_bound(mk(y,Node(0,0)));
		Node cur=t->se;
		if(t->fi==y){
			adj[x].erase(mk(y,cur)),adj[x].insert(mk(y,twist(cur,w)));
			adj[y].erase(mk(x,cur)),adj[y].insert(mk(x,twist(cur,w)));
		}
		else adj[x].insert(mk(y,w)),adj[y].insert(mk(x,w));
	};
	
	for(int i=1;i<=n;i++){
		int l=dfn[i],r=dfn[i]+sz[i]-1;
		int L=lower_bound(a+1,a+m+1,l)-a;
		int R=upper_bound(a+1,a+m+1,r)-a-1;
		adde(L,R+1,Node(val[i],1));
	}
	
	m++;
	auto chk=[&](int x){
		if(inq[x])return ;
		if(adj[x].size()<=2)q.push(x),inq[x]=1;
	};
	
	for(int i=1;i<=m;i++)chk(i);
	for(int i=1;i<=m;i++)if(find(i)!=find(1))return puts("0"),0;
	
	int ans=1;
	while(q.size()){
		int x=q.front();q.pop();
		if(adj[x].size()==1){
			auto t=adj[x].begin();int y=t->fi;Node w=t->se;
			ans=1ll*ans*w.f%mod;
			adj[y].erase(mk(x,w)),chk(y);
		}
		else if(adj[x].size()==2){
			auto p=adj[x].begin(),q=--adj[x].end();
			int y=p->fi,z=q->fi;auto wy=p->se,wz=q->se;
			adj[y].erase(mk(x,wy)),adj[z].erase(mk(x,wz));
			Node w=Node(1ll*wy.f*wz.f%mod,cmod(1ll*wy.f*wz.g%mod+1ll*wy.g*wz.f%mod));
			auto r=adj[y].lower_bound(mk(z,Node(0,0)));
			if(r->fi!=z)adj[y].insert(mk(z,w)),adj[z].insert(mk(y,w));
			else{
				auto u=r->se;
				auto v=Node(cmod(1ll*w.f*u.g%mod+1ll*u.f*w.g%mod),1ll*w.g*u.g%mod);
				adj[y].erase(mk(z,u)),adj[y].insert(mk(z,v));
				adj[z].erase(mk(y,u)),adj[z].insert(mk(y,v));
				chk(y),chk(z);
			}
		}
	}
	
	cout<<ans<<endl;

	return 0;
}

标签:Node,LOJ3626,int,mk,1ll,QOJ4889,愚蠢,adj,mod
From: https://www.cnblogs.com/YunQianQwQ/p/17775501.html

相关文章

  • 记一次愚蠢的svg使用。。。
    问题描述参考了老师的写的优雅使用iconfontvue引入iconfont的优雅实践确实很优雅,感谢老师,但是我脑残把use里的xlink:href写成xlink-href,导致我一直拿不到iconTT经常因为这点小错误就浪费一下午,痛定思痛记一下我的代码代码vue.config.js...chainWebpack(config){co......
  • 我那愚蠢的代码之旅
    在编程的世界里,每个人都曾有过初学者时期,那个时候,我们充满了好奇和渴望,但也不免陷入了迷茫和混乱。我将借此机会,与您分享我那段令人难忘的编程初体验,那段充满了繁复、愚蠢和迷茫,却也锻造了我如今的编程能力。让我们一同走进我的编程时光隧道,重温那个曾让我笑与泪交加的糟糕时光。我......
  • 《愚蠢的错误》最新 DLC:手残错误大合集
    插入/删除/修改字符不超过10B能不挂分的我认为是手残错误。注释freopen(典中典,\(0\))测试大样例freopen错(典,\(1\))手残删行(\(1\))在小改代码后自信不再测大样例导致对的改错(\(1\))......
  • 记录一下这次关于死循环使用愚蠢的行为
    在一个多线程的使用场景下,有个变量标记线程是否退出,然后我有这么一行代码while(!stopRequest){}这个问题是cpu某个核会一直占用,正确做法是在loop中sleep一段时间,例如1毫秒,10毫秒,100毫秒。让Cpu资源释放出去,sleep的时间越短,cpu资源就越紧张......
  • 【程序人生】保持清醒,认清自己;保持饥饿,充实自己;保持愚蠢,学会做人
    ......
  • 记一道超级愚蠢的leetcode的题
    是513. 找树左下角的值,这道题里面根节点是否是左节点根本就不统一,它在没有左节点的时候是左节点,在右节点有左叶子的时候又不是左节点。     我把我的代码附......