20200924day20 刷题记录

1 严格次小生成树

题目大意

对于无向图(G),我们记最小生成树的边集为(E_m),次小生成树的边集为(E_p),用( ext{value}(x))表示(x)的边权,则严格次小生成树满足(sumlimits_{xin E_m} ext{value}(x)<sumlimits_{xin E_p} ext{value}(x)),请你求出其边权。

题解

对于最小生成树,删去一条边后形成两个联通块,任意连接两个联通块的边,最小的边即为次小生成树。严格的意思是,连接的这个边严格大于删掉的边,如果等于了,也叫次小生成树。

代码

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define int long long
#define M 300003
using namespace std;
inline int read(){
	int f=1,x=0;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+(c^48);c=getchar();}
	return x*f;
}
struct node1{
	int x,y,z,flag;
}w[M];

struct node2{
	int to,next,val;
}edge[M];
#define INF 2100000001
#define N 100003
int cnt,m,n,minn=INF,ans=0;
int f[N][22],max1[N][22],g[N][22],fa[N],head[N],dep[N];
bool cmp(node1 a,node1 b){
	return a.z<b.z;
}
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void add(int x,int y,int v){
	cnt++;
	edge[cnt].val=v;
	edge[cnt].to=y;
	edge[cnt].next=head[x];
	head[x]=cnt;
}
void krs(){
	int q=1;
	sort(w+1,w+m+1,cmp);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++){
		int s1=find(w[i].x);
		int s2=find(w[i].y);
		if(s1!=s2){
			ans+=w[i].z;w[i].flag=1;
			q++;
			fa[s1]=s2;
			add(w[i].x,w[i].y,w[i].z);
			add(w[i].y,w[i].x,w[i].z);
		}
		if(q==n) break;
	}
}
void dfs(int x){
		for(int i=head[x];i;i=edge[i].next){
			int v=edge[i].to;
			if(v==f[x][0]) continue;
			f[v][0]=x;
			max1[v][0]=edge[i].val;
			dep[v]=dep[x]+1;
			for(int j=1;j<=20;j++){
				if(dep[v]<(1<<j)) break;
				f[v][j]=f[f[v][j-1]][j-1];
				max1[v][j]=max(max1[v][j-1],max1[f[v][j-1]][j-1]);
				if(max1[v][j-1]==max1[f[v][j-1]][j-1])
				 g[v][j]=max(g[v][j-1],g[f[v][j-1]][j-1]);//g是次小边
				else{
					g[v][j]=min(max1[v][j-1],max1[f[v][j-1]][j-1]);
					g[v][j]=max(g[v][j],g[f[v][j-1]][j-1]);
					g[v][j]=max(g[v][j-1],g[v][j]);
				}
				
			}
			dfs(v);
		}
}
int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=20;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
	if(v==u) return v;
	for(int i=20;i>=0;i--) if(f[v][i]!=f[u][i]) v=f[v][i],u=f[u][i];
	return f[v][0];
}
void change(int x,int lca,int val){
	int maxx1=0,maxx2=0;
	int d=dep[x]-dep[lca];
	for(int i=0;i<=20;i++){
		if(d<(1<<i)) break;
		if(d&(1<<i)){
			if(max1[x][i]>maxx1){
				maxx2=max(maxx1,g[x][i]);
				maxx1=max1[x][i];
			}
			x=f[x][i];
		}
	}
	if(val!=maxx1) minn=min(minn,val-maxx1);
	else minn=min(minn,val-maxx2);
}
void work(){
	for(int i=1;i<=m;i++){
		if(!w[i].flag){
			int s1=w[i].x,s2=w[i].y;
			int lcp=lca(s1,s2);
			change(s1,lcp,w[i].z);change(s2,lcp,w[i].z);
		}
	}
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&w[i].x,&w[i].y,&w[i].z);
	}
	krs();
	dfs(1);
	work();
	printf("%lld
",ans+minn);
	return 0;
}

2 逆序对[树状数组维护]

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxx=1000005;
ll a[maxx],b[maxx],s[maxx];
ll n;
void init()
{
	sort(b+1,b+1+n);
	unique(b+1,b+1+n);//-b-1;
	for(ll i=1;i<=n;i++)
	{
		a[i]=lower_bound(b+1,b+n+1,a[i])-b;
	}
	return;
}
int main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		b[i]=a[i];
	}
	ll ans=0;
	init();
	for(ll i=n;i>=1;i--)
	{
		for(ll j=a[i];j<=n;j+=(j&-j))
		{
			s[j]++;
		}
		for(ll j=a[i]-1;j>=1;j-=(j&-j))
		{
			ans+=s[j];
		}
	}
	printf("%lld",ans);	
	return 0;
}
要做就做南波万
原文地址:https://www.cnblogs.com/liuziwen0224/p/20200924day20-001.html