2020.10.26模拟赛
T1 炎热的夏季
考虑两次dijkstra,第一次找出经过最热路径温度的最小值,第二次在温度小于等于这个值的边上跑最短路,得到最少流汗数。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+5,M=1e6+5,inf=9223372036854775807;
const int BUFFER_SIZE = 1 << 30;
char rb[BUFFER_SIZE], *rp = rb, *rt = rb;
inline char read_char() {
return rp == rt ? (rt = rb + fread(rb, 1, BUFFER_SIZE, stdin), rp = rb, *rp ++) : *rp ++;
}
inline int read_int() {
int x = 0;
char ch = read_char(), flag = 0;
while (ch != '-' && (ch < '0' || ch > '9')) {
ch = read_char();
}
if (ch == '-') {
flag = 1;
ch = read_char();
}
for (x = 0; ch >= '0' && ch <= '9'; ch = read_char()) {
x = x * 10 + (ch - '0');
}
return flag ? -x : x;
}
int n,m,a,b,vis[N],dis[N];
int line[M][4];
vector<pair<int,int> >v[N];
vector<pair<int,int> > v1[N];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
int dijstra1(){
for(int i=1;i<=n;i++)vis[i]=inf;
vis[a]=0;
q.push(make_pair(0,a));
while(q.size()){
int x=q.top().second,z=q.top().first;q.pop();
if(vis[x]<z)continue;
for(unsigned int i=0;i<v[x].size();i++){
int y=v[x][i].first,tem=v[x][i].second;
if(vis[y]>max(z,tem)){
vis[y]=max(z,tem);
q.push(make_pair(vis[y],y));
}
}
}
return vis[b];
}
void dijstra2(){
for(int i=1;i<=n;i++)dis[i]=inf;
dis[a]=0;
q.push(make_pair(0,a));
while(q.size()){
int x=q.top().second,z=q.top().first;q.pop();
if(dis[x]<z)continue;
for(unsigned int i=0;i<v1[x].size();i++){
int y=v1[x][i].first,len=v1[x][i].second;
if(dis[y]>z+len){
dis[y]=z+len;
q.push(make_pair(dis[y],y));
}
}
}
}
signed main(){
freopen("hot4.in","r",stdin);
cin>>n>>m;
for(int i=1;i<=m;i++){
line[i][0]=read_int(),line[i][1]=read_int(),line[i][2]=read_int(),line[i][3]=read_int();
v[line[i][0]].push_back(make_pair(line[i][1],line[i][2]));
v[line[i][1]].push_back(make_pair(line[i][0],line[i][2]));
}
a=read_int(),b=read_int();
int maxn=dijstra1();
for(int i=1;i<=m;i++){
if(line[i][2]>maxn)continue;
v1[line[i][0]].push_back(make_pair(line[i][1],1ll*line[i][3]*line[i][2]));
v1[line[i][1]].push_back(make_pair(line[i][0],1ll*line[i][3]*line[i][2]));
}
dijstra2();
cout<<maxn<<' '<<dis[b];
return 0;
}
T2 奇数的田园
经过推理可以发现,要使得每一个点度数为奇数,当且仅当每一个连通块的大小为偶数。
然后再在每一个连通块中处理。
#include<bits/stdc++.h>
using namespace std;
const int M=5e5+5,N=2e5+5;
const int BUFFER_SIZE = 1 << 20;
char rb[BUFFER_SIZE], *rp = rb, *rt = rb;
inline char read_char() {
return rp == rt ? (rt = rb + fread(rb, 1, BUFFER_SIZE, stdin), rp = rb, *rp ++) : *rp ++;
}
inline int read_int() {
int x = 0;
char ch = read_char(), flag = 0;
while (ch != '-' && (ch < '0' || ch > '9')) {
ch = read_char();
}
if (ch == '-') {
flag = 1;
ch = read_char();
}
for (x = 0; ch >= '0' && ch <= '9'; ch = read_char()) {
x = x * 10 + (ch - '0');
}
return flag ? -x : x;
}
int n,m,fa[N],o,size[N],son[N];
bool mark[M],vis[N];
vector<pair<int,int> > v[N];
struct node{
int x,y,z,id;
}l[M];
bool cmp(node a,node b){
return a.z<b.z;
}
int gf(int x){
if(x==fa[x])return x;
fa[x]=gf(fa[x]);
return fa[x];
}
void dfs(int x){
vis[x]=1;
for(int i=0;i<v[x].size();i++){
int y=v[x][i].first,id=v[x][i].second;
if(vis[y])continue;
dfs(y);
if(son[y]%2==0)mark[id]=1,son[x]++;
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
l[i].x=read_int(),l[i].y=read_int(),l[i].z=read_int();
l[i].id=i;
}
sort(l+1,l+m+1,cmp);
o=n;
for(int i=1;i<=n;i++)fa[i]=i,size[i]=1;
int i;
for(i=1;o&&i<=m;i++){
int x=gf(l[i].x),y=gf(l[i].y);
if(x!=y){
if(size[y]%2==1&&size[x]%2==1)o-=2;
fa[x]=y;
size[y]+=size[x];
}
v[l[i].x].push_back(make_pair(l[i].y,l[i].id));
v[l[i].y].push_back(make_pair(l[i].x,l[i].id));
}
if(i>m&&o){
cout<<-1;
return 0;
}
cout<<l[i-1].z<<endl;
for(int i=1;i<=n;i++){
if(vis[i])continue;
dfs(i) ;
}
for(int i=1;i<=m;i++)putchar(mark[i]+'0');
return 0;
}
T3 意念的交流
卡常毒瘤题!!!!!!!
卡了我一个晚自习!!!
两个点之间交流的代价是路径中最大的边权,由此想到kruskal重构树,对于每一条边建立一个虚拟节点,将边从小到大排序,如果边的两端不在同一子树内,就都向这条边的虚拟节点连一条边。易证,两个点路径上的最大边权就是他们LCA的点权。
计算每一条边作为LCA的贡献,当且仅当两个点分别在它的两个子树中,并且满足\(abs(c[i]-c[j])>=l\)。
就在重构树上dfs序,以dfs序为一维,再把c[i],c[i]-l,c[i]+l离散化,作为第二维,跑二维数点。
时间复杂度\(O(nlog^2n)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=2e6+5,N=1e5+5;
const int BUFFER_SIZE = 1 << 20;
char rb[BUFFER_SIZE], *rp = rb, *rt = rb;
inline char read_char() {
return rp == rt ? (rt = rb + fread(rb, 1, BUFFER_SIZE, stdin), rp = rb, *rp ++) : *rp ++;
}
inline int read_int() {
int x = 0;
char ch = read_char(), flag = 0;
while (ch != '-' && (ch < '0' || ch > '9')) {
ch = read_char();
}
if (ch == '-') {
flag = 1;
ch = read_char();
}
for (x = 0; ch >= '0' && ch <= '9'; ch = read_char()) {
x = x * 10 + (ch - '0');
}
return flag ? -x : x;
}
int n,m,L,c[M],d[M],e[M],fa[M],cnt,val[M],in[M],out[M],ls[M],rs[M],size[M],tot;
int js,num[M],t[M];
ll ans;
struct aaa{
int a,b;
ll w;
bool d;
bool operator < (const aaa& b)const{
return a==b.a?d<b.d:a<b.a;
}
}a[5*M];
struct node{
int x,y,z;
bool operator < (const node& b)const{
return z<b.z;
}
}l[M];
struct bbb{
int a,id;
bool operator < (const bbb& b)const{
return a<b.a;
}
}li[M];
inline int gf(int x){
if(x==fa[x])return x;
fa[x]=gf(fa[x]);
return fa[x];
}
inline void kruskal(){
for(int i=1;i<=n;i++)fa[i]=i;
sort(l+1,l+m+1);
cnt=n;
for(int i=1;i<=m;i++){
int x=gf(l[i].x),y=gf(l[i].y);
if(x!=y){
val[++cnt]=l[i].z;
fa[x]=cnt,fa[y]=cnt,fa[cnt]=cnt;
ls[cnt]=x,rs[cnt]=y;
}
}
}
int p=0;
inline void dfs1(int x){
if(x<=n)in[x]=++p;
if(x<=n)size[x]=1;
if(ls[x])dfs1(ls[x]);
if(rs[x])dfs1(rs[x]);
size[x]+=size[ls[x]]+size[rs[x]];
if(!in[x])in[x]=in[ls[x]];
out[x]=p;
}
inline void dfs2(int x){
if(!ls[x])return;
if(size[ls[x]]>size[rs[x]])swap(ls[x],rs[x]);
a[++tot].a=in[rs[x]]-1,a[tot].b=js,a[tot].w=1ll*-val[x]*size[ls[x]],a[tot].d=1;
a[++tot].a=out[rs[x]],a[tot].b=js,a[tot].w=1ll*val[x]*size[ls[x]],a[tot].d=1;
int l=in[rs[x]],r=out[rs[x]],w=val[x];
for(int i=in[ls[x]];i<=out[ls[x]];i++){
int y=num[i];
a[++tot].a=l-1,a[tot].b=d[y],a[tot].w=-w,a[tot].d=1;
a[++tot].a=l-1,a[tot].b=e[y]-1,a[tot].w=w,a[tot].d=1;
a[++tot].a=r,a[tot].b=d[y],a[tot].w=w,a[tot].d=1;
a[++tot].a=r,a[tot].b=e[y]-1,a[tot].w=-w,a[tot].d=1;
}
if(ls[x])dfs2(ls[x]);
if(rs[x])dfs2(rs[x]);
}
inline void add(int x){
for(int i=x;i<=js;i+=i&-i)t[i]++;
}
inline int getsum(int x){
int sum=0;
for(int i=x;i>=1;i-=i&-i)sum+=t[i];
return sum;
}
signed main(){
n=read_int(),m=read_int(),L=read_int();
for(int i=1;i<=n;i++){
c[i]=read_int();
li[i].a=c[i],li[i].id=i;
li[n+i].a=c[i]-L;li[n+i].id=n+i;
li[n+n+i].a=L==0?c[i]+1:c[i]+L;li[n+n+i].id=n+n+i;
}
sort(li+1,li+3*n+1);
js=1;
for(int i=1;i<=3*n;i++){
if(li[i].a>li[i-1].a)js++;
c[li[i].id]=js;
}
for(int i=1;i<=n;i++)d[i]=c[n+i],e[i]=c[n+n+i];
for(int i=1;i<=m;i++)l[i].x=read_int(),l[i].y=read_int(),l[i].z=read_int();
kruskal();
dfs1(cnt);
for(int i=1;i<=n;i++)num[in[i]]=i;
dfs2(cnt);
for(int i=1;i<=n;i++){
a[++tot].a=in[i],a[tot].b=c[i],a[tot].d=0;
}
sort(a+1,a+tot+1);
for(int i=1;i<=tot;i++){
if(a[i].d){
ans+=1ll*getsum(a[i].b)*a[i].w;
}
else add(a[i].b);
}
cout<<ans;
return 0;
}
T4 信号的覆盖
把f数组从大到小排序,找到每一个点的父亲,再判断是否正确。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
long long n,size[N],fa[N],dep[N];
struct node{
long long v;int id;
}f[N];
bool cmp(node a,node b){return a.v>b.v;}
map<long long,int> m;
vector<int> v[N];
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa)continue;
dfs(y,x);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&f[i].v);
f[i].id=i;
}
sort(f+1,f+n+1,cmp);
for(int i=1;i<=n;i++)size[i]=1,m[f[i].v]=i;
for(int i=1;i<n;i++){
long long x=f[i].v+2*size[i]-n;
int y=m[x];
if(!y||y==i){
cout<<-1;
return 0;
}
fa[i]=y;
size[y]+=size[i];
}
for(int i=1;i<n;i++){
v[fa[i]].push_back(i);
v[i].push_back(fa[i]);
}
dep[1]=-1;
dfs(1,1);
long long sum=0;
for(int i=1;i<=n;i++){sum+=dep[i];}
if(sum!=f[1].v){
cout<<-1;
return 0;
}
for(int i=1;i<n;i++){
printf("%d %d\n",f[i].id,f[fa[i]].id);
}
return 0;
}
总结
A题比较稳,拿到了100分,BCD不会,其实如果更加深入地思考D题,离正确结论已经不远了。

浙公网安备 33010602011771号