<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【做題記錄】圖論相關問題

      A. 牛場圍欄
      首先判斷 -1 的情況。

      • 如果可用的長度中有 \(1\),那么所有長度都能拼出來。
      • 如果所有可用長度的 \(gcd\) 不為 \(1\),那一定沒有最大值。
        • 證明:設 \(gcd\)\(q\),則 \(q\mid x_1a_1+x_2a_2+\dots+x_na_n,x_1,x_2,\dots,x_n\in\mathbb{Z}\)。那么對于不能被 \(q\) 整除的數,就一定拼不出來。

      然后考慮最小的能拼出來的數,顯然就是最小的可用長度,記為 \(mina\),考慮它的每個剩余系 \(K_i,i=0,1,\dots mina-1\),因為有解,所以一定存在一個最小的能拼出來的 \(t_i=mina\times p+i\),因為 \(mina\) 是最小的所以 \(p\) 一定大于 \(0\)。則對于 \(K_i\) 最大的拼不出來的數就是 \(t_i-mina\)\(t_i\) 可用同余最短路來求,就是說每個 \(K_i\) 都是一個點,每個可用長度都是一條邊。使用樸素 Dijkstra,時間復雜度為 \(O(mina^2)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      #define gcd __gcd
      #define pb push_back
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=3e3+5,inf=0x3f3f3f3f;
      int n,m,a[maxn],mina=maxn,dis[maxn];
      bool vis[maxn];
      vector<pii> e[maxn];
      il void wuj(){
      	int tmp=0;
      	for(int i=1;i<=3e3;i++){
      		if(vis[i]){
      			tmp=gcd(tmp,i);
      		}
      	}
      	if(tmp>1||vis[1]){
      		puts("-1");
      		exit(0);
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	read(n)read(m);
      	for(int i=1;i<=n;i++){
      		read(a[i]);
      		for(int j=0;j<=min(m,a[i]);j++){
      			vis[a[i]-j]=1;
      		}
      	}
      	for(int i=1;i<3e3;i++){
      		if(vis[i]){
      			mina=i;
      			break;
      		}
      	}
      	wuj();
      	memset(dis,0x3f,sizeof dis);
      	for(int i=1;i<3e3;i++){
      		if(!vis[i]){
      			continue;
      		}
      		dis[i%mina]=min(dis[i%mina],i);
      		for(int j=0;j<mina;j++){
      			e[j].pb(mp((j+i)%mina,i));
      		}
      	}
      	memset(vis,0,sizeof vis);
      	for(int i=1,u,v,w,mind;i<=mina;i++){
      		mind=inf;
      		for(int j=0;j<mina;j++){
      			if(mind>dis[j]&&!vis[j]){
      				mind=dis[j],u=j;
      			}
      		}
      		vis[u]=1;
      		for(pii j:e[u]){
      			v=j.fir,w=j.sec;
      			if(!vis[v]&&dis[v]>dis[u]+w){
      				dis[v]=dis[u]+w;
      			}
      		}
      	}
      	int ans=0;
      	for(int i=0;i<mina;i++){
      		ans=max(ans,dis[i]-mina);
      	}
      	printf("%d",ans);
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. 「LNOI2014」LCA
      將深度轉化,其實就是這個點到根的路徑上的點的個數。
      對于每個詢問 \(l,r,u\),將 \(\forall i\in[l,r]\) 到根都權值加一,再求 \(u\) 到根的權值和。樹剖 \(+\) 線段樹。
      考慮離線,每個詢問在 \(l-1\) 處減,在 \(r\) 處加,從 \(1\)\(n\) 掃一遍就行了。

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      #define pb push_back
      #define lid id<<1
      #define rid id<<1|1
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=5e4+5,mod=201314;
      int n,m,fa[maxn],ans[maxn];
      int dfn[maxn],cnt;
      int top[maxn],sz[maxn],hes[maxn];
      vector<int> e[maxn];
      vector<pii> hao[maxn];
      il void dfs1(int u){
      	sz[u]=1;
      	int mxs=0;
      	for(int v:e[u]){
      		dfs1(v);
      		sz[u]+=sz[v];
      		if(mxs<sz[v]){
      			mxs=sz[v];
      			hes[u]=v;
      		}
      	}
      }
      il void dfs2(int u){
      	dfn[u]=++cnt;
      	if(!top[u]){
      		top[u]=u;
      	}
      	if(hes[u]){
      		top[hes[u]]=top[u];
      		dfs2(hes[u]);
      	}
      	for(int v:e[u]){
      		if(v!=hes[u]){
      			dfs2(v);
      		}
      	}
      }
      int sum[maxn<<2],tag[maxn<<2];
      il void pushup(int id){
      	sum[id]=(sum[lid]+sum[rid])%mod;
      }
      il void pushtag(int id,int l,int r,int val){
      	(tag[id]+=val)%=mod;
      	(sum[id]+=(r-l+1)*val)%=mod;
      }
      il void pushdown(int id,int l,int r){
      	if(tag[id]){
      		int mid=(l+r)>>1;
      		pushtag(lid,l,mid,tag[id]);
      		pushtag(rid,mid+1,r,tag[id]);
      		tag[id]=0;
      	}
      }
      il void upd(int id,int L,int R,int l,int r,int val){
      	if(L>=l&&R<=r){
      		pushtag(id,L,R,val);
      		return ;
      	}
      	pushdown(id,L,R);
      	int mid=(L+R)>>1;
      	if(l<=mid){
      		upd(lid,L,mid,l,r,val);
      	}
      	if(r>mid){
      		upd(rid,mid+1,R,l,r,val);
      	}
      	pushup(id);
      }
      il int query(int id,int L,int R,int l,int r){
      	if(L>=l&&R<=r){
      		return sum[id];
      	}
      	pushdown(id,L,R);
      	int mid=(L+R)>>1,res=0;
      	if(l<=mid){
      		(res+=query(lid,L,mid,l,r))%=mod;
      	}
      	if(r>mid){
      		(res+=query(rid,mid+1,R,l,r))%=mod;
      	}
      	return res;
      }
      il void upd(int u,int val){
      	while(top[u]!=1){
      		upd(1,1,n,dfn[top[u]],dfn[u],val);
      		u=fa[top[u]];
      	}
      	upd(1,1,n,dfn[1],dfn[u],val);
      }
      il int query(int u){
      	int res=0;
      	while(top[u]!=1){
      		(res+=query(1,1,n,dfn[top[u]],dfn[u]))%=mod;
      		u=fa[top[u]];
      	}
      	return (res+query(1,1,n,dfn[1],dfn[u]))%mod;
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      	read(n)read(m);
      	for(int i=2;i<=n;i++){
      		read(fa[i]);
      		e[++fa[i]].pb(i);
      	}
      	dfs1(1),dfs2(1);
      //	for(int i=1;i<=n;i++){
      //		cout<<dfn[i]<<" ";
      //	}
      //	puts("");
      	for(int i=1,l,r,u;i<=m;i++){
      		read(l)read(r)read(u);
      		u++;
      		hao[l].pb(mp(-i,u)),hao[r+1].pb(mp(i,u));
      	}
      	for(int i=1;i<=n;i++){
      		upd(i,1);
      		for(pii j:hao[i]){
      			if(j.fir<0){
      				(ans[-j.fir]+=mod-query(j.sec))%=mod;
      			}
      			else{
      				(ans[j.fir]+=query(j.sec))%=mod;
      			}
      		}
      	}
      	for(int i=1;i<=m;i++){
      		printf("%lld\n",ans[i]);
      	}
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      

      C. 跳跳棋
      考慮每個狀態(tài) \((x,y,z),x<y<z\) 的轉移:

      1. \(y\) 移到左邊:\((2x-y,x,z)\)
      2. \(y\) 移到右邊:\((x,z,2z-y)\)
      3. \(x\) 移到中間:\((y,2y-x,z)\)
      4. \(z\) 移到中間:\((x,2y-z,y)\)

      \(3\)\(4\) 個轉移是矛盾的。具體地,設 \(d1=y-x\)\(d2=z-y\),若 \(d1<d2\) 則可以進行 第 \(3\) 個轉移,若 \(d1>d2\) 則可以進行第 \(4\) 個轉移,否則不可轉移。
      我們令 \((x,y,z)\) 進行了 \(3\)\(4\) 號操作后的狀態(tài)為它的父親。則它的父親可以通過第 \(1\)\(2\) 個轉移到達它。則對于每一個狀態(tài),可以找到它所屬的二叉樹。二叉樹的根就是那個 \(d1=d2\) 的狀態(tài)。而我們要求的就是兩個狀態(tài)在樹上的距離(如果所在的樹不一樣則無解)。
      求樹上的距離的方式為求 \(lca\)。考慮如何去求。首先讓兩個狀態(tài)走到同一深度,然后二分 \(lca\) 的高度,判斷這個高度的祖先是否相同。
      那么問題就在于如何快速求出某個狀態(tài)的深度與 \(k\) 級祖先了。我們考慮壓縮轉移。以第 \(3\) 個轉移為例,最多可以連續(xù)進行 \(\lfloor\frac{d2-1}{d1}\rfloor\) 次。設 \(tmp=\lfloor\frac{d2-1}{d1}\rfloor\)\(tmp\) 次轉移后的狀態(tài)即為 \((x+tmp\times d1,y+tmp\times d2,z)\)。這樣我們最多跳 \(\log\max(d1,d2)\) 次。于是這兩個操作的時間復雜度就都是 \(\log\) 級別的了。因為還有個二分,最終的復雜度是 \(\log^2\) 的。

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      struct node{
      	int a[3];
      	il void init(){
      		sort(a,a+3);
      	}
      	il int&operator[](int x){
      		return a[x];
      	}
      	il bool operator==(node x)const{
      		return a[0]==x[0]&&a[1]==x[1]&&a[2]==x[2];
      	}
      	il bool operator!=(node x)const{
      		return !(*this==x);
      	}
      };
      il int dep(node x){
      	int d1=x[1]-x[0],d2=x[2]-x[1];
      	int res=0;
      	while(d1!=d2){
      		if(d1>d2){
      			int tmp=(d1-1)/d2;
      			x[1]-=tmp*d2,x[2]-=tmp*d2;
      			res+=tmp;
      		}
      		else{
      			int tmp=(d2-1)/d1;
      			x[0]+=tmp*d1,x[1]+=tmp*d1;
      			res+=tmp;
      		}
      		d1=x[1]-x[0],d2=x[2]-x[1];
      	}
      	return res;
      }
      il node ganc(node x,int k){
      	int d1=x[1]-x[0],d2=x[2]-x[1];
      	while(k){
      		if(d1>d2){
      			int tmp=min((d1-1)/d2,k);
      			x[1]-=tmp*d2,x[2]-=tmp*d2;
      			k-=tmp;
      		}
      		else{
      			int tmp=min((d2-1)/d1,k);
      			x[0]+=tmp*d1,x[1]+=tmp*d1;
      			k-=tmp;
      		}
      		d1=x[1]-x[0],d2=x[2]-x[1];
      	}
      	return x;
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      	node p,q;
      	read(p[0])read(p[1])read(p[2]);
      	read(q[0])read(q[1])read(q[2]);
      	p.init(),q.init();
      	int dp=dep(p),dq=dep(q);
      //	cout<<dp<<" "<<dq<<"\n";
      	if(ganc(p,dp)!=ganc(q,dq)){
      		puts("NO");
      		return 0;
      	}
      	if(dp<dq){
      		swap(dp,dq),swap(p,q);
      	}
      	p=ganc(p,dp-dq);
      	int l=0,r=dq;
      	while(l<r){
      		int mid=(l+r)>>1;
      		if(ganc(p,mid)==ganc(q,mid)){
      			r=mid;
      		}
      		else{
      			l=mid+1;
      		}
      	}
      	puts("YES");
      	printf("%lld",dp-dq+l*2);
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      

      D. Berland and the Shortest Paths
      對圖進行 bfs,顯然這樣生成的樹是滿足要求的。
      因此我們只需計算對于每個點,哪些邊是從上一層連下來的。所有點這個邊數的乘積就是總方案數。
      輸出方案就對每一個點枚舉選哪條邊即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      #define pb push_back
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      int n,m,tot,num[maxn];
      int vis[maxn],dep[maxn];
      vector<int> hao[maxn];
      vector<pii> e[maxn];
      queue<int> q;
      il void dfs(int u){
      	if(u>n){
      		for(int i=1;i<=m;i++){
      			printf("%d",vis[i]);
      		}
      		puts("");
      		if(--tot==0){
      			exit(0);
      		}
      		return ;
      	}
      	for(int x:hao[u]){
      		vis[x]=1;
      		dfs(u+1);
      		vis[x]=0;
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	read(n)read(m)read(tot);
      	for(int i=1,u,v;i<=m;i++){
      		read(u)read(v);
      		e[u].pb(mp(v,i));
      		e[v].pb(mp(u,i));
      	}
      	dep[1]=1,q.push(1);
      	while(q.size()){
      		int u=q.front();
      		q.pop();
      		for(pii i:e[u]){
      			int v=i.fir,w=i.sec;
      			if(!dep[v]){
      				dep[v]=dep[u]+1;
      				num[v]++,hao[v].pb(w);
      				q.push(v);
      			}
      			else if(dep[u]+1==dep[v]){
      				num[v]++,hao[v].pb(w);
      			}
      		}
      	}
      	ll res=1;
      	for(int i=2;i<=n;i++){
      		res*=num[i];
      		if(res>=tot){
      			break;
      		}
      	}
      	tot=min(tot*1ll,res);
      	printf("%d\n",tot);
      	dfs(2);
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      E. Breaking Good
      首先 bfs 搞出最短路。
      設最短路為 \(dep\),本來完好的邊數為 \(sum\),則對于一條最短路徑 \(i\),設其中本來完好的邊數為 \(cnt\),則答案為 \((dep-cnt)+(sum-cnt)\)。所以只需讓 \(cnt\) 最大。在 bfs 時轉移即可。題目還要求輸出方案,因此需要記錄路徑。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5;
      int n,m,enm,dep[maxn];
      int cnt[maxn],hd[maxn],pre[maxn];
      bool vis[maxn],zai[maxn],hp[maxn];
      queue<int> q;
      struct edge{
      	int v,w,id,nxt;
      }e[maxn<<1];
      il void addedge(int u,int v,int w,int id){
      	e[++enm]=(edge){v,w,id,hd[u]};
      	hd[u]=enm;
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	read(n)read(m);
      	int sum=0;
      	for(int i=1,u,v,w;i<=m;i++){
      		read(u)read(v)read(w);
      		addedge(u,v,w,i);
      		addedge(v,u,w,i);
      		sum+=w;
      	}
      	memset(cnt,-1,sizeof cnt);
      	cnt[1]=0;
      	vis[1]=1,q.push(1);
      	while(q.size()){
      		int u=q.front();
      		q.pop();
      		for(int i=hd[u],v,w;i;i=e[i].nxt){
      			v=e[i].v,w=e[i].w;
      			if(vis[v]&&dep[v]<=dep[u]){
      				continue;
      			}
      			if(!vis[v]){
      				dep[v]=dep[u]+1;
      				vis[v]=1,q.push(v);
      			}
      			if(cnt[v]<cnt[u]+w){
      				cnt[v]=cnt[u]+w;
      				pre[v]=u;
      			}
      		}
      	}
      	printf("%d\n",dep[n]+sum-2*cnt[n]);
      //	for(int i=1;i<=n;i++){
      //		cout<<pre[i]<<"\n";
      //	}
      	int u=n;
      	while(u!=1){
      		for(int i=hd[pre[u]],v,w,id;i;i=e[i].nxt){
      			v=e[i].v,w=e[i].w,id=e[i].id;
      			if(v==u){
      				zai[id]=1;
      				if(!w){
      					printf("%d %d %d\n",pre[u],u,1);
      				}
      				break;
      			}
      		}
      		u=pre[u];
      	}
      	for(u=1;u<=n;u++){
      		for(int i=hd[u],v,w,id;i;i=e[i].nxt){
      			v=e[i].v,w=e[i].w,id=e[i].id;
      			if(hp[id]){
      				continue;
      			}
      			hp[id]=1;
      			if(!zai[id]&&w){
      				printf("%d %d %d\n",u,v,0);
      			}
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      F. Turtle and Intersected Segments
      對于三個能互相連邊的點 \((l_i,r_i,a_i),(l_j,r_j,a_j),(l_k,r_k,a_k)\),其中 \(a_i\le a_j\le a_k\),我們顯然只需要將 \(i\)\(j\) 連邊,\(j\)\(k\) 連邊就夠了。
      于是進行掃描線,加入每個點時去找它的 \(a\) 值的前驅和后繼連邊。用 set 維護。
      set::insert 的返回值為一個 pair,其中 first 為插入的這個值的迭代器,second 是一個 bool,表示有沒有插入成功(因為 set 去重)。類似地 multiset 只返回一個迭代器。
      可以用 prev(it) 返回 \(it\) 的前一個迭代器,next 返回后一個。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      #define int ll
      #define pb push_back
      #define lwrb lower_bound
      #define uprb upper_bound
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=5e5+5;
      int n,lsh[maxn<<1];
      int fa[maxn],sz[maxn];
      struct node{
      	int l,r,a;
      }p[maxn];
      vector<int> hao[maxn<<1];
      struct cmp{
      	il bool operator()(const int &x,const int &y)const{
      		if(p[x].a==p[y].a){
      			return x>y;
      		}
      		return p[x].a<p[y].a;
      	}
      };
      set<int,cmp> hp;
      struct edge{
      	int u,v,w;
      	il bool operator<(const edge &x)const{
      		return w<x.w;
      	}
      }e[maxn<<1];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      il void solve(){
      	read(n);
      	int tot=0;
      	for(int i=1;i<=n;i++){
      		read(p[i].l)read(p[i].r)read(p[i].a);
      		lsh[++tot]=p[i].l;
      		lsh[++tot]=p[i].r;
      	}
      	sort(lsh+1,lsh+tot+1);
      	tot=unique(lsh+1,lsh+tot+1)-lsh-1;
      	for(int i=1;i<=n;i++){
      		hao[lwrb(lsh+1,lsh+tot+1,p[i].l)-lsh].pb(i);
      		hao[lwrb(lsh+1,lsh+tot+1,p[i].r)-lsh].pb(-i);
      	}
      	for(int i=1;i<=tot;i++){
      		sort(hao[i].begin(),hao[i].end(),greater<int>());
      	}
      	hp.clear();
      	int num=0;
      	for(int i=1;i<=tot;i++){
      		for(int u:hao[i]){
      			if(u<0){
      				hp.erase(-u);
      				continue;
      			}
      			auto tmp=hp.insert(u).first;
      			if(tmp!=hp.begin()){
      				e[++num]=(edge){*prev(tmp),u,p[u].a-p[*prev(tmp)].a};
      			}
      			if(next(tmp)!=hp.end()){
      				e[++num]=(edge){u,*next(tmp),p[*next(tmp)].a-p[u].a};
      			}
      		}
      	}
      	for(int i=1;i<=n;i++){
      		fa[i]=i,sz[i]=1;
      	}
      	sort(e+1,e+num+1);
      	int cnt=0,ans=0;
      	for(int i=1;i<=num;i++){
      		if(find(e[i].u)!=find(e[i].v)){
      			merge(e[i].u,e[i].v);
      			cnt++,ans+=e[i].w;
      		}
      	}
      	printf("%lld\n",cnt==n-1?ans:-1);
      	for(int i=1;i<=tot;i++){
      		hao[i].clear();
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      	int T;
      	read(T);
      	while(T--){
      		solve();
      	}
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      

      G. MST Company
      首先將所有與 \(1\) 相連的邊去掉,求一個最小生成森林。然后對于每個連通塊,從 \(1\) 向它連一條最小的邊。此時如果邊不夠或需要連的邊超出限制就無解。
      然后去滿足 \(k\) 的限制。從沒有被選中的從 \(1\) 連出的邊中選一條連上,則要從形成的這個環(huán)上刪去一條邊(端點不能為 \(1\))。顯然刪去最大的一條。設新連的邊為 \(w1\),最大的邊為 \(w2\),則要求 \(w1-w2\) 最小。每次 \(O(n)\) 掃一遍即可。總復雜度 \(O(nk)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      const int inf=0x3f3f3f3f;
      int n,m,num,enm=1,hd[maxn];
      int fa[maxn],sz[maxn];
      vector<int> vec,ans;
      struct edge{
      	int u,v,w,id,nxt;
      	il bool operator<(const edge &x)const{
      		return w<x.w;
      	}
      }a[maxn],e[maxn];
      il void addedge(int u,int v,int w,int id){
      	e[++enm].v=v;
      	e[enm].w=w;
      	e[enm].id=id;
      	e[enm].nxt=hd[u];
      	hd[u]=enm;
      }
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      int mx[maxn];
      bool ban[maxn],no[maxn];
      il void dfs(int u,int fa){
      //	cout<<u<<"\n";
      	for(int i=hd[u],v;i;i=e[i].nxt){
      		v=e[i].v;
      		if(ban[i]||v==fa||v==1){
      			continue;
      		}
      		mx[v]=e[mx[u]].w>e[i].w?mx[u]:i;
      		dfs(v,u);
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m>>num;
      	for(int i=1;i<=m;i++){
      		cin>>a[i].u>>a[i].v>>a[i].w;
      		if(a[i].u>a[i].v){
      			swap(a[i].u,a[i].v);
      		}
      		a[i].id=i;
      	}
      	sort(a+1,a+m+1);
      	for(int i=1;i<=n;i++){
      		fa[i]=i,sz[i]=1;
      	}
      	for(int i=1;i<=m;i++){
      		if(a[i].u==1){
      			continue;
      		}
      		if(find(a[i].u)!=find(a[i].v)){
      			merge(a[i].u,a[i].v);
      			addedge(a[i].u,a[i].v,a[i].w,a[i].id);
      			addedge(a[i].v,a[i].u,a[i].w,a[i].id);
      			ans.pb(a[i].id);
      		}
      	}
      	for(int i=1;i<=m;i++){
      		if(a[i].u==1){
      			if(find(a[i].u)==find(a[i].v)){
      				vec.pb(i);
      			}
      			else{
      				merge(a[i].u,a[i].v);
      				addedge(a[i].u,a[i].v,a[i].w,a[i].id);
      				addedge(a[i].v,a[i].u,a[i].w,a[i].id);
      				ans.pb(a[i].id);
      				num--;
      			}
      		}
      	}
      	if(num<0||num>vec.size()){
      		puts("-1");
      		return 0;
      	}
      	for(int i=1;i<n;i++){
      		if(find(i)!=find(i+1)){
      			puts("-1");
      			return 0;
      		}
      	}
      	for(int i=1;i<=num;i++){
      //		puts("666");
      		for(int j=1;j<=n;j++){
      			mx[j]=0;
      		}
      		for(int j=hd[1];j;j=e[j].nxt){
      //			cout<<e[j].v<<":\n";
      			dfs(e[j].v,1);
      		}
      //		for(int j=1;j<=n;j++){
      //			cout<<mx[j]<<" ";
      //		}
      //		cout<<"\n";
      		int mn=inf,tmp;
      		for(int j=0;j<vec.size();j++){
      			if(mn>a[vec[j]].w-e[mx[a[vec[j]].v]].w){
      				mn=a[vec[j]].w-e[mx[a[vec[j]].v]].w;
      				tmp=j;
      			}
      		}
      //		cout<<a[vec[tmp]].v<<"\n";
      		ban[mx[a[vec[tmp]].v]]=ban[mx[a[vec[tmp]].v]^1]=1;
      		no[e[mx[a[vec[tmp]].v]].id]=1;
      //		cout<<a[tmp].v<<"\n";
      //		cout<<a[mx[a[tmp].v]].id<<"\n";
      		addedge(a[vec[tmp]].u,a[vec[tmp]].v,a[vec[tmp]].w,a[vec[tmp]].id);
      		addedge(a[vec[tmp]].v,a[vec[tmp]].u,a[vec[tmp]].w,a[vec[tmp]].id);
      		ans.pb(a[vec[tmp]].id);
      		vec.erase(vec.begin()+tmp);
      	}
      	cout<<n-1<<"\n";
      	for(int i:ans){
      		if(!no[i]){
      			cout<<i<<" ";
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      H. DFS Trees
      邊權互不相同,則最小生成樹只有一棵。
      將最小生成樹邊打上標記,那么我們要求在以 \(i\) 點為根 dfs 時打上標記的邊成為樹邊。換句話說,要求沒被打上標記的邊成為返祖邊。
      對于一條沒被標記的邊 \((u,v)\),我們要求 dfs 時能走完它所在的環(huán)上其它的邊,設 \(dep_u<dep_v\),考慮兩種情況:

      1. \(lca(u,v)=u\),則只有根在 \(v\) 的子樹內或 \(u\) 對應 \(v\) 的兒子的子樹外時滿足。
      2. 否則,只有根在 \(u\)\(v\) 的子樹中時才可滿足。

      對于每條邊給能滿足的點權值加一,最后查詢每個點的權值是否為 \(m-(n-1)\) 就好了。可以用樹狀數組。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      #define pb push_back
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      const int inf=0x3f3f3f3f;
      int n,m,cnt,anc[22][maxn];
      int fa[maxn],sz[maxn],dep[maxn];
      int top[maxn],dfn[maxn],hes[maxn];
      bool vis[maxn];
      pii a[maxn];
      vector<pii> e[maxn];
      struct dsu{
      	int fa[maxn],sz[maxn];
      	il void init(){
      		for(int i=1;i<=n;i++){
      			fa[i]=i,sz[i]=1;
      		}
      	}
      	il int find(int x){
      		return x!=fa[x]?fa[x]=find(fa[x]):x;
      	}
      	il void merge(int u,int v){
      		u=find(u),v=find(v);
      		if(u==v){
      			return ;
      		}
      		if(sz[u]>sz[v]){
      			sz[u]+=sz[v],fa[v]=u;
      		}
      		else{
      			sz[v]+=sz[u],fa[u]=v;
      		}
      	}
      	il bool check(int u,int v){
      		return find(u)==find(v);
      	}
      }D;
      il void dfs1(int u){
      //	cout<<u<<"\n";
      	anc[0][u]=fa[u];
      	for(int i=1;i<=20;i++){
      		anc[i][u]=anc[i-1][anc[i-1][u]];
      	}
      	dep[u]=dep[fa[u]]+1;
      	sz[u]=1;
      	int mxs=0;
      	for(pii i:e[u]){
      		int v=i.fir;
      		if(!vis[i.sec]||v==fa[u]){
      			continue;
      		}
      		fa[v]=u;
      		dfs1(v);
      		sz[u]+=sz[v];
      		if(mxs<sz[v]){
      			mxs=sz[v];
      			hes[u]=v;
      		}
      	}
      }
      il void dfs2(int u){
      	dfn[u]=++cnt;
      	if(!top[u]){
      		top[u]=u;
      	}
      	if(hes[u]){
      		top[hes[u]]=top[u];
      		dfs2(hes[u]);
      	}
      	for(pii i:e[u]){
      		int v=i.fir;
      		if(!vis[i.sec]||v==fa[u]||v==hes[u]){
      			continue;
      		}
      		dfs2(v);
      	}
      }
      il int lca(int u,int v){
      	while(top[u]!=top[v]){
      		if(dep[top[u]]<dep[top[v]]){
      			swap(u,v);
      		}
      		u=fa[top[u]];
      	}
      	return dep[u]<dep[v]?u:v;
      }
      il int ganc(int u,int k){
      	int tmp=0;
      	while(k){
      		if(k&1){
      			u=anc[tmp][u];
      		}
      		k>>=1,tmp++;
      	}
      	return u;
      }
      struct fenwick{
      	int tr[maxn];
      	il int lowbit(int x){
      		return x&-x;
      	}
      	il void upd(int pos,int val){
      //		cout<<pos<<"\n";
      		for(;pos<=n;pos+=lowbit(pos)){
      			tr[pos]+=val;
      		}
      	}
      	il int query(int pos){
      		int res=0;
      		for(;pos;pos-=lowbit(pos)){
      			res+=tr[pos];
      		}
      		return res;
      	}
      }F;
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	read(n)read(m);
      	for(int i=1,u,v;i<=m;i++){
      		read(u)read(v);
      		a[i]=mp(u,v);
      		e[u].pb(mp(v,i));
      		e[v].pb(mp(u,i));
      	}
      	D.init();
      	for(int i=1;i<=m;i++){
      		if(!D.check(a[i].fir,a[i].sec)){
      			D.merge(a[i].fir,a[i].sec);
      			vis[i]=1;
      		}
      	}
      //	puts("666");
      	dfs1(1),dfs2(1);
      //	puts("777");
      	for(int i=1,u,v;i<=m;i++){
      		if(!vis[i]){
      			u=a[i].fir,v=a[i].sec;
      			if(dep[u]>dep[v]){
      				swap(u,v);
      			}
      //			cout<<u<<" "<<v<<"\n";
      			if(lca(u,v)==u){
      				F.upd(1,1);
      				u=ganc(v,dep[v]-dep[u]-1);
      //				puts("777");
      				F.upd(dfn[u],-1);
      				F.upd(dfn[u]+sz[u],1);
      				F.upd(dfn[v],1);
      				F.upd(dfn[v]+sz[v],-1);
      			}
      			else{
      //				puts("666");
      				F.upd(dfn[u],1);
      //				puts("777");
      				F.upd(dfn[u]+sz[u],-1);
      //				puts("888");
      				F.upd(dfn[v],1);
      //				puts("999");
      				F.upd(dfn[v]+sz[v],-1);
      //				puts("777");
      			}
      		}
      	}
      	for(int i=1;i<=n;i++){
      		printf("%d",F.query(dfn[i])==m-n+1);
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      I. The Shortest Statement
      \(m-n\le20\),則當我們搞出一棵生成樹時最多剩下 \(21\) 條邊。相應地會對答案產生改變的點最多有 \(42\) 個。對這些點跑 dijkstra 即可。

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      #define read(x){\
      	char ch;\
      	int fu=1;\
      	while(!isdigit(ch=getchar()))\
      		fu-=(ch=='-')<<1;\
      	x=ch&15;\
      	while(isdigit(ch=getchar()))\
      		x=(x<<1)+(x<<3)+(ch&15);\
      	x*=fu;\
      }
      #define pb push_back
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+25;
      int n,m,q;
      int fa[maxn],sz[maxn];
      int dep[maxn],hes[maxn];
      int top[maxn],tis[maxn];
      int dis[50][maxn];
      bool vis[maxn],viss[maxn];
      vector<pii> e[maxn];
      struct edge{
      	int u,v,w;
      }a[maxn];
      il int find(int x){
      	return x!=fa[x]?fa[x]=find(fa[x]):x;
      }
      il void merge(int u,int v){
      	u=find(u),v=find(v);
      	if(u==v){
      		return ;
      	}
      	if(sz[u]>sz[v]){
      		sz[u]+=sz[v],fa[v]=u;
      	}
      	else{
      		sz[v]+=sz[u],fa[u]=v;
      	}
      }
      il void dfs1(int u){
      	dep[u]=dep[fa[u]]+1;
      	sz[u]=1;
      	int mxs=0;
      	for(pii i:e[u]){
      		int v=i.fir,w=i.sec;
      		if(v==fa[u]){
      			continue;
      		}
      		tis[v]=tis[u]+w;
      		fa[v]=u;
      		dfs1(v);
      		sz[u]+=sz[v];
      		if(mxs<sz[v]){
      			mxs=sz[v];
      			hes[u]=v;
      		}
      	}
      }
      il void dfs2(int u){
      	if(!top[u]){
      		top[u]=u;
      	}
      	if(hes[u]){
      		top[hes[u]]=top[u];
      		dfs2(hes[u]);
      	}
      	for(pii i:e[u]){
      		int v=i.fir,w=i.sec;
      		if(v==fa[u]||v==hes[u]){
      			continue;
      		}
      		dfs2(v);
      	}
      }
      il int tdis(int u,int v){
      	int tu=u,tv=v;
      	while(top[u]!=top[v]){
      		if(dep[top[u]]<dep[top[v]]){
      			swap(u,v);
      		}
      		u=fa[top[u]];
      	}
      	if(dep[u]>dep[v]){
      		swap(u,v);
      	}
      	return tis[tu]+tis[tv]-tis[u]*2;
      }
      il void dijkstra(int s,int *dis){
      	priority_queue<pii> q;
      	memset(viss,0,sizeof viss);
      	dis[s]=0,q.push(mp(0,s));
      	while(q.size()){
      		int u=q.top().sec,v,w;
      		q.pop(),viss[u]=1;
      		for(pii i:e[u]){
      			v=i.fir,w=i.sec;
      			if(!viss[v]&&dis[v]>dis[u]+w){
      				dis[v]=dis[u]+w;
      				q.push(mp(-dis[v],v));
      			}
      		}
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      	read(n)read(m);
      	for(int i=1,u,v,w;i<=m;i++){
      		read(u)read(v)read(w);
      		a[i]=(edge){u,v,w};
      	}
      	for(int i=1;i<=n;i++){
      		fa[i]=i,sz[i]=1;
      	}
      	for(int i=1,u,v;i<=m;i++){
      		u=a[i].u,v=a[i].v;
      		if(find(u)!=find(v)){
      			merge(u,v);
      			e[u].pb(mp(v,a[i].w));
      			e[v].pb(mp(u,a[i].w));
      		}
      		else{
      			vis[a[i].u]=vis[a[i].v]=1;
      		}
      	}
      	memset(fa,0,sizeof fa);
      	dfs1(1),dfs2(1);
      	for(int i=1;i<=n;i++){
      		e[i].clear();
      	}
      	for(int i=1,u,v,w;i<=m;i++){
      		u=a[i].u,v=a[i].v,w=a[i].w;
      		e[u].pb(mp(v,w));
      		e[v].pb(mp(u,w));
      	}
      	memset(dis,0x3f,sizeof dis);
      	int tot=0;
      	for(int i=1;i<=n;i++){
      		if(vis[i]){
      			dijkstra(i,dis[++tot]);
      		}
      	}
      	read(q);
      	while(q--){
      		int u,v;
      		read(u)read(v);
      		int res=tdis(u,v);
      		for(int i=1;i<=tot;i++){
      			res=min(res,dis[i][u]+dis[i][v]);
      		}
      		printf("%lld\n",res);
      	}
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      
      posted @ 2025-01-21 16:12  zhangxy__hp  閱讀(33)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品内射在线免费看| 瑞安市| 亚洲av成人无码精品电影在线 | 亚洲AV无码国产永久播放蜜芽 | 亚洲精品美女一区二区| 亚洲女同精品久久女同| 成人伊人青草久久综合网| 亚洲熟妇自偷自拍另类| 亚洲人成网站18禁止| 国产精品免费久久久免费| 久久国产精品乱子乱精品| 亚洲欧洲中文日韩久久av乱码| 通海县| 人妻av无码系列一区二区三区 | 香蕉亚洲欧洲在线一区| XXXXXHD亚洲日本HD| 亚洲av日韩av中文高清性色| 无码熟妇人妻av影音先锋| 亚洲18禁一区二区三区| 东京热人妻丝袜无码AV一二三区观| av无码精品一区二区乱子| 亚洲欧美日韩成人综合一区| 亚洲午夜福利网在线观看| 免费人妻无码不卡中文18禁| 久久亚洲国产精品五月天| 少女韩国在线观看完整版免费| 航空| 中文国产人精品久久蜜桃| 永久免费av网站可以直接看的| 亚洲人成网站999久久久综合| 成全我在线观看免费第二季| 国产美女永久免费无遮挡| 欧美亚洲综合成人A∨在线| 麻豆国产传媒精品视频| 精品人妻一区二区三区蜜臀| 午夜福利片1000无码免费| 人人干人人噪人人摸| 久久久久影院色老大2020| 蜜臀91精品国产高清在线| 午夜无码国产18禁| 国产一区二区一卡二卡|