Loading

CSP 后多校十二

A. 开挂

签到题.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	#define int long long 
	#define lf long double
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define lbt(x) ((x)&(-(x)))
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		for(;!isdigit(ch);ch=getchar()) cit=(ch=='-');
		for(;isdigit(ch);ch=getchar()) w=(w<<3)+(w<<1)+(ch^48);
		return cit?(-w):w;
	};
} using namespace BSS;

#define ull unsigned int 

const int N=1e6+21,inf=1e15;

ull fans;
ull b[N],ans[N];

int m,n,cnt;
int a[N];
pair<int,int> stk[N];
signed main(){
	File(openhook);
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++) b[i]=read();
	sort(a+1,a+1+n,[](int i,int j){ return i>j; }),sort(b+1,b+1+n);
	for(int i=1;i<=n;i++) a[i]-=a[n]-1;
	stk[++cnt]=mp(a[1]+1,inf),ans[1]=0;
	for(int i=2;i<=n;i++){
		if(a[i]^a[i-1]) stk[++cnt]=mp(a[i],a[i-1]-1);
		pair<int,int> now=stk[cnt--];
		ans[i]=now.first-a[i];
		if(now.first<now.second) stk[++cnt]=mp(now.first+1,now.second);
	}
	sort(ans+1,ans+1+n,[](ull i,ull j){ return i>j; });
	for(int i=1;i<=n;i++) fans+=ans[i]*b[i];
	printf("%llu\n",fans),exit(0);
}

B. 叁仟柒佰万

签到题.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	// #define int long long 
	#define lf long double
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define lbt(x) ((x)&(-(x)))
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	const int Mxdt=100005;
	auto gc=[]()->char{
		static char buf[Mxdt],*p1=buf,*p2=buf;
		return p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
	};
	auto read=[]()->int{
		int t=0,f=0;char v=gc();
		while(v<'0')f|=(v=='-'),v=gc();
		while(v>='0')t=(t<<3)+(t<<1)+v-48,v=gc();
		return f?-t:t;
	};
} using namespace BSS;

#define LL long long 
const LL mod=1e9+7;
const int N=37000021,M=37000000;

int m,n,st,cnt,minx,ans;
int val[N],pre[N],vis[N];
auto ksm=[](int a,int b,int c,int w=1)->int{
	for(a%=c;b;b>>=1,a=1ll*a*a%c) if(b&1) w=1ll*w*a%c;
	return w%c;
};
auto inc=[](int i,int j)->int{ i+=j; return i-(i>=mod)*mod; }; 
auto Work=[]()->void{
	n=read(),st=0,cnt=0,ans;
	for(int i=0;i<=n;i++) vis[i]=0,pre[i]=0;
	if(n==37000000){
		int x=read(),y=read(); val[1]=0;
		for(int i=2;i<=n;i++) val[i]=(1ll*val[i-1]*x+y+i)&262143ll;
	}
	else for(int i=1;i<=n;i++) val[i]=read();
	for(int i=1;i<=n;i++) vis[val[i]]=1;
	for(int i=0;i<=n;i++) if(!vis[i]) { minx=i; break; }
	if(!minx) { printf("%d\n",ksm(2,n-1,mod)); return ; }
	for(int i=0;i<=minx+5;i++) vis[i]=0;
	pre[0]=1;
	for(int i=1;i<=n;i++){
		pre[i]=1; 
		if(val[i]>minx) continue; 
		cnt+=(!vis[val[i]]),vis[val[i]]++;
		if(cnt==minx) { st=i,pre[i]=2; break; } 
	}
	for(int i=st+1,j=0;i<=n;i++){
		vis[val[i]]++;
		while(j<i){
			if(val[j+1]>minx){ j++; continue; }
			else if(vis[val[j+1]]>1) j++,vis[val[j]]--;
			else break;
		}
		// cout<<"i and j: "<<i<<' '<<j<<endl;
		ans=pre[j],pre[i]=inc(pre[i-1],ans);
	}
	printf("%d\n",ans);
};
signed main(){
	File(clods);
	for(int Ts=read();Ts;Ts--) Work();
	exit(0);
}

C. 超级加倍

可以想到 \(Kruscal\) 重构树,(因为昨天刚刚刷了杂题..

正解由部分分中链的笛卡尔树启发而来了 \(Kruscal\).

本题中想办法构造一种重构树满足任意两点之间的最大/小点是 \(lca\) 即可,感觉有点套路.

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	// #define int long long 
	#define lf long double
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define lbt(x) ((x)&(-(x)))
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		for(;!isdigit(ch);ch=getchar()) cit=(ch=='-');
		for(;isdigit(ch);ch=getchar()) w=(w<<3)+(w<<1)+(ch^48);
		return cit?(-w):w;
	};
} using namespace BSS;

#define LL long long int 
const int N=2e6+21;

LL ans;
int m,n,rt,ts,cnt;
int fa[N],dfn[N],head[N],siz[N];
vector<int> to[N];
struct I { int u,v,nxt; } e[N<<1];
struct FenWick{
	int res; int c[N<<1];
	inline void upd(int x,int w){
		for(x++;x<=n+1;x+=lbt(x)) c[x]+=w;
	}
	inline int qry(int x){
		for(x++,res=0;x;x&=x-1) res+=c[x]; return res;
	}
}bit;
inline int find(int x){ return fa[x]==x ? x : fa[x]=find(fa[x]) ; }
auto add=[](int u,int v)->void{
	e[++ts].u=u,e[ts].v=v,e[ts].nxt=head[u];
	head[u]=ts;
};
inline void sch(int u){
	dfn[u]=++cnt,siz[u]=1;
	for(int i=head[u];i;i=e[i].nxt) sch(e[i].v),siz[u]+=siz[e[i].v];
}
inline void dfs(int u){
	ans+=0ll+bit.qry(dfn[u]+siz[u]-1)-bit.qry(dfn[u]-1);
	bit.upd(dfn[u],1);
	for(int i=head[u];i;i=e[i].nxt) dfs(e[i].v);
	bit.upd(dfn[u],-1);
}
signed main(){
	File(charity);
	n=read(),read(),fa[1]=1; int u,v,w,x,y,z;
	for(int i=2;i<=n;i++){
		v=read(),to[i].pb(v),to[v].pb(i),fa[i]=i;
	}
	for(int i=n;i>=1;i--){
		for(auto j : to[i]){
			if(j>i and (find(j)^i)) add(i,find(j)),fa[find(j)]=i;
		}
	}
	for(int i=1;i<=n;i++) if(find(i)==i){ rt=i; break; }
	sch(rt); ts=0; 
	for(int i=1;i<=n;i++) fa[i]=i,head[i]=0;
	for(int i=1;i<=n;i++){
		for(auto j : to[i]){
			if(j<i and (find(j)^i)) add(i,find(j)),fa[find(j)]=i;
		}
	}
	for(int i=1;i<=n;i++) if(find(i)==i){ rt=i; break; }
	dfs(rt); printf("%lld\n",ans);
	exit(0);
}

D. 欢乐豆

一步步分析问题.(考场上直接没时间想直接死了,还是时间思考不够..)

首先考虑 \(x,y\) 两点之间的最短距离可能由什么构成,仔细想一想部分分和题目其实并不是很难.

如果 \(m==0\),那么其实 \(x\) 到其它点的最短距离一定是 \(a_x\).

对于 \(m\) 不是 \(0\) 的情况.

假设修改的边为 \(path\{u,v\}\),那么 \(u,v\) 两点之间的最短距离要么是 \(a_u\),要么是通过中间的某个点 \(x\)到达 \(v\),即 \(dis\{u,x\}+a_x\).

于是我们发现考虑哪些点会作为 \(u\) 的中间点即可,也就是我们需要求出所有和修改有关的点到其它点的 \(dis\).

很暴力的思想就是跑全源最短路,但是发现图是完全图的话,那么复杂度直接变成 \(O(m^3log)\).

依旧是考虑尽量少枚举重复或无用的信息,那么发现对于题里给的 \(m\) 条边中没有出现的 \(path\{u,v\}\) 的情况,\(u,v\) 两点的直接距离依然是 \(a_u\) ,发现这样的 \(v\) 对于点 \(u\) 很多,于是线段树就好了.

也就是在跑全源最短路的过程中,模拟 \(dijkstra\),线段树维护一些修改和最小值就好了.

好像还有一些 \(dalao\) 直接把线段树去掉,选择把贡献移到单点上,很牛逼.

D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
	#define int long long 
	#define lf long double
	#define pb push_back
	#define mp make_pair
	#define lb lower_bound
	#define ub upper_bound
	#define lbt(x) ((x)&(-(x)))
	#define Fill(x,y) memset(x,y,sizeof(x))
	#define Copy(x,y) memcpy(x,y,sizeof(x))
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
		for(;!isdigit(ch);ch=getchar()) cit=(ch=='-');
		for(;isdigit(ch);ch=getchar()) w=(w<<3)+(w<<1)+(ch^48);
		return cit?(-w):w;
	};
} using namespace BSS;

#define ls (x<<1)
#define rs (x<<1|1)
const int N=1e6+21,inf=1e15;

int m,n,cnt,ts,ans;
int val[N],fa[N],siz[N],vis[N],dfn[N],rk[N],dis[N];
vector<int> vec;
vector<pair<int,int> > to[N];
multiset<int> s;
unordered_map<int,int> ed[N];
struct I { int up,mn,id,lzy; } tr[N<<2];
int find(int x){ return x==fa[x] ? x : fa[x]=find(fa[x]) ; }
auto getval=[](int x,int l,int r,int w)->void{
	if(l==r and tr[x].up) return ;
	if(tr[x].mn<=w) return tr[x].lzy=min(tr[x].lzy,w),tr[x].mn=min(tr[x].lzy,tr[x].mn),void();
	tr[x].lzy=min(tr[x].lzy,w),tr[x].mn=min(tr[x].mn,tr[x].lzy);
};
auto spread=[](int x,int l,int r)->void{
	int &lzy=tr[x].lzy,mid=(l+r)>>1; 
	if(lzy==inf or tr[x].up) return ;
	getval(ls,l,mid,lzy),getval(rs,mid+1,r,lzy),lzy=inf;
};
auto pushup=[](int x)->void{
	if(tr[ls].up and tr[rs].up) return tr[x].mn=inf,tr[x].up=1,tr[x].id=0,void();
	if(tr[ls].up) return tr[x].id=tr[rs].id,tr[x].mn=tr[rs].mn,void();
	if(tr[rs].up) return tr[x].id=tr[ls].id,tr[x].mn=tr[ls].mn,void();
	tr[x].mn=min(tr[ls].mn,tr[rs].mn);
	tr[x].id= (tr[x].mn==tr[ls].mn ? tr[ls].id : tr[rs].id);
	// cout<<"xid:"<<x<<" "<<tr[x].id<<' '<<tr[x].mn<<' '<<tr[ls].mn<<' '<<tr[rs].mn<<' '<<tr[ls].id<<' '<<tr[rs].id<<" der\n";
};
void build(int x,int l,int r){
	tr[x].lzy=inf,tr[x].id=0,tr[x].mn=inf,tr[x].up=0;
	if(l==r) return tr[x].id=rk[l],tr[x].mn=dis[rk[l]],void();
	int mid=(l+r)>>1; build(ls,l,mid),build(rs,mid+1,r);
	pushup(x);
}
void upd(int x,int l,int r,int px,int w){
	if(l==r) return tr[x].id=0,tr[x].mn=w,tr[x].up=1,tr[x].lzy=inf,void();
	int mid=(l+r)>>1;  spread(x,l,r);
	(px<=mid) ? upd(ls,l,mid,px,w) : upd(rs,mid+1,r,px,w);
	pushup(x);
}
void change(int x,int l,int r,int ql,int qr,int w){
	if(ql>qr or tr[x].up) return ;
	if(l>=ql and r<=qr) return getval(x,l,r,w);
	int mid=(l+r)>>1; spread(x,l,r);
	if(ql<=mid) change(ls,l,mid,ql,qr,w);
	if(qr>mid) change(rs,mid+1,r,ql,qr,w);
	pushup(x);
}
auto bfs=[](int x)->void{
	int minval=inf,dad=x;
	for(auto i : vec) dis[i]=val[x];
	dis[x]=0;  // cout<<"x:"<<x<<endl;
	for(auto i : to[x]) dis[i.first]=i.second;
	build(1,1,cnt);
	for(int i=1,k;i<=cnt;i++,x=tr[1].id){
		dis[x]=tr[1].mn,k=1;
		// cout<<"dis:"<<x<<' '<<dis[x]<<' '<<dfn[x]<<"\n";
		// cout<<"newid:"<<tr[1].id<<' '<<tr[1].mn<<endl;
		for(auto j : to[x]){
			int v=j.first;
			change(1,1,cnt,k,dfn[v]-1,val[x]+dis[x]);
			change(1,1,cnt,dfn[v],dfn[v],dis[x]+j.second);
			k=dfn[v]+1;
		}
		change(1,1,cnt,k,cnt,val[x]+dis[x]),upd(1,1,cnt,dfn[x],inf);
	}
	// cout<<"begin:"<<*s.begin()<<endl;
	for(auto i : vec) ans+=min(dis[i],*s.begin()+val[dad]);
	// for(auto i : vec) cout<<min(dis[i],*s.begin()+val[dad])<<' '; puts("");
	// for(auto i : vec) cout<<dis[i]<<' '; puts("");
	for(auto i : vec) minval=min(minval,dis[i]+val[i]);
	// cout<<"minval:"<<minval<<endl;
	// cout<<"ans:"<<ans<<endl;
	ans+=minval*(n-cnt);
};
auto Work=[](int x)->void{
	for(int i=1;i<=n;i++) if(find(i)==x) vec.pb(i);
	cnt=vec.size(),sort(vec.begin(),vec.end());
	for(int i=0;i<cnt;i++) rk[dfn[vec[i]]=i+1]=vec[i];
	// for(int i=1;i<=cnt;i++) cout<<rk[i]<<' '; puts("");
	for(auto i : vec) s.erase(s.find(val[i]));
	for(auto i : vec) bfs(i); vec.clear();
	for(auto i : vec) s.insert(val[i]);
};
signed main(){
	File(happybean);
	n=read(),m=read(),s.insert(inf);; int u,v,w,x,y,z;
	for(int i=1;i<=n;i++) val[i]=read(),fa[i]=i,s.insert(val[i]);
	for(int i=1;i<=m;i++){
		u=read(),v=read(),w=read();
		if(ed[u].find(v)!=ed[u].end()) to[u][ed[u][v]]=mp(v,w);
		else to[u].pb(mp(v,w)),fa[find(u)]=find(v),ed[u][v]=to[u].size()-1;
	}
	for(int i=1;i<=n;i++) siz[find(i)]++,sort(to[i].begin(),to[i].end());
	for(int i=1;i<=n;i++){
		if(siz[find(i)]==1){ ans+=val[i]*(n-1); continue ; }
		if(vis[find(i)]) continue;
		vis[find(i)]=1,Work(find(i));
	}
	printf("%lld\n",ans),exit(0);
}
posted @ 2021-11-11 06:05  AaMuXiiiiii  阅读(82)  评论(0编辑  收藏  举报