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题,离正确结论已经不远了。

posted @ 2020-10-27 21:52  蒟蒻_william555  阅读(79)  评论(0)    收藏  举报