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);
}