暑假D23

Seq

老师给两个人一个1...n的排列,让大家抄下来,结果小明和李华都各自抄错了一个数,他们决定结合两人的序列弄出原序列。不存在输出“Impossible”,多种可能输出字典序小的。

1<=n<=1e5

题解

一个恶心的模拟,可以发现一个性质:原来是排列,如果抄错一个那么就会有一个数出现两遍。

然后总结一下这道题就是:两个序列有且只有一个错误,且错误只在重复的数中产生。

那么首先分别找到重复的位置(如果多个重复或者没重复就不存在),然后再分别求出少的那个数。

然后开始快乐的分类讨论:

1.两者两个重复的位置都相同:

   如果除了这两个位置其他有不一样的地方就错了。
   两者重复的数要么是相同的要么就是对方少的那一个,所以前面的位置取一个小的数就好。

2.有一个位置相同 

   如果除了这三个位置其他有不一样的地方就错了。
   相同的位置数也相同,那么这个数一定是原序列的数,可以简单模拟,如果不是那么剩下两个位置都是正确的,但是数又相同显然不可能。
   相同的位置数不同,那么必然有一个是错的或者两个都是错的,就看剩下两个位置和另外一个序列的相同位置上的数相不相同,以为另外一个序列上那个位置一定是对的。看代码就好了,我感觉讨论多了,因为有些东西懒得证明就保险一点。

3.没有位置相同

   根据只有重复的位置可能错这个性质判断就好了,代码这里有点不保险以为没看第二个序列。
#include<bits/stdc++.h>
using namespace std;
//两个序列分别有且只有一个错误,错误只在重复的数中产生 
const int maxn=100005;
int n,a[maxn],b[maxn];
int c1[maxn],c2[maxn];
int pos1[3],pos2[3];
int mex1,mex2;
bool opt;

void print(){
    for(int i=1;i<=n;i++) printf("%d\n",a[i]);
    exit(0);
}

void get(int l,int j){//pos1[l]==pos2[j]
  for(int i=1;i<=n;i++){
      if(i==pos1[1]||i==pos1[2]||i==pos2[1]||i==pos2[2]) continue;
      if(a[i]!=b[i]){
          printf("Impossible");
            exit(0);
        }
    }
  int k= l==1 ? 2 : 1,p= j==1 ? 2 : 1 ;
    if(pos1[0]==pos2[0]){//数相同,一定是原序列的数 
        if(mex1==b[pos1[k]]&&mex2==a[pos2[p]]){
            a[pos1[k]]=mex1;
            print();
        } 
        else{
            printf("Impossible");
            exit(0);
        }
    }
    else {
        if(a[pos1[k]]==b[pos1[k]]){
            if(a[pos2[p]]==b[pos2[p]]){
                if(mex1==mex2) {
                    a[pos1[l]]=mex1;
                    print();
                }
                else {
                    printf("Impossible");
                exit(0);
                }
            }
            else if(mex1==b[pos1[l]]&&mex2==a[pos2[p]]){
                a[pos1[l]]=mex1;
                print();
            }
            else {
                printf("Impossible");
              exit(0);
            }
        }
        else {
            if(b[pos1[k]]==mex1&&a[pos2[p]]==b[pos2[p]]){
                a[pos1[k]]=mex1;
                print();
            }
            else {
                printf("Impossible");
              exit(0);
            }
        }
    }
}

int main(){
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(!c1[a[i]]) c1[a[i]]++;
        else if(!opt){
            pos1[0]=a[i];
            pos1[2]=i;
            opt=true;
        }
        else {//有多个重复 
            printf("Impossible");
            return 0;
        }
    }
    opt=false;
    for(int i=1;i<=n;i++) {
        scanf("%d",&b[i]);
        if(!c2[b[i]]) c2[b[i]]++;
        else if(!opt){
            pos2[0]=b[i];
            pos2[2]=i;
            opt=true;
        }
        else {
            printf("Impossible");
            return 0;
        }
    }
    if(!pos1[0]||!pos2[0]){//有一个序列没有重复的数 
        printf("Impossible");
        return 0;
    }
    for(int i=1;i<=n;i++)//找到重复的两个位置 
        if(a[i]==pos1[0]){
            pos1[1]=i;
            break;
        }
    for(int i=1;i<=n;i++)
        if(b[i]==pos2[0]){
            pos2[1]=i;
            break;
        }
    for(int i=1;i<=n;i++)if(!c1[i]){mex1=i;break;}//找到序列缺少的那个元素 
    for(int i=1;i<=n;i++)if(!c2[i]){mex2=i;break;}
    if(pos1[1]==pos2[1]&&pos1[2]==pos2[2]){//位置相同
      for(int i=1;i<=n;i++){
          if(i==pos1[1]||i==pos1[2]) continue;
          if(a[i]!=b[i]){
              printf("Impossible");
              exit(0);
            }
        }
        //序列相同或者另外一个序列上就是缺的那个 
        if(mex1<pos1[0]) a[pos1[1]]=mex1;
        else a[pos1[2]]=mex1;
        print();
    }
    if(pos1[1]==pos2[1]) get(1,1);
    if(pos1[2]==pos2[2]) get(2,2);
    if(pos1[1]==pos2[2]) get(1,2);
    if(pos1[2]==pos2[1]) get(2,1);
    //没有位置相同
    if(a[pos1[1]]==b[pos1[1]]){
        a[pos1[2]]=b[pos1[2]];
        print();
  }
    if(a[pos1[2]]==b[pos1[2]]){
        a[pos1[1]]=b[pos1[1]];
        print();
    }
    printf("Impossible");
}
seq

有点恶心,甚至感觉自己没写对。


Work

有一个公司在一条笔直的公路上,坐标为x。它有n个员工,每个员工有一所住宅坐标为$a_{i}$,这条路还有m个打卡机,坐标为$b_{i}$。每天员工从住宅出发,经过任意一个打卡机打卡,然后再去公司,每个打卡机只能为一个员工打卡。

所有人同时出发,求所有人打卡并达到公司,所经过的最短时间,假设一个人移动一个单位需要一单位时间,打卡不需要时间。

1<=n<=m<=1e5,$1<=a_{i},b_{i},x<=1e9$

题解

考试的时候以为很难,也看出了二分,不过不知道咋check。

那么正解就是先对所有人和打卡机排序,每个人选择他所能选的最左边的打卡机,这个应该是因为既然可以选的话就给后面的人多留一点。(或者sxk dalao的方法就是选择不能交叉,可以证明?)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100005;
const ll oo=2000000000;
int n,m,x;
int a[maxn],b[maxn];

ll get(int i,int j){return abs(a[i]-b[j])+abs(b[j]-x);}

bool check(ll mid){
    for(int i=1,j=1;i<=n;i++){
        while(j<=m&&get(i,j)>mid) j++;
        if(j>m) return false;
        j++;
    }
    return true;
}

int main(){
    freopen("work.in","r",stdin);
    freopen("work.out","w",stdout);
    scanf("%d%d%d",&n,&m,&x);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    ll l=0,r=oo,ans;
    while(l<=r){
        ll mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%lld",ans);
}
work

Tree

给一个带权连同无向图,对于每条边求一个最大的整数权值k,使得把这条边的权值改成k(其他边权不变),整个图的任意一个最小生成树都有这条边。

无论权值为多少都在生成树上输出-1

1<=n,m<=1e5,$1<=w_{i}<=1e9$

题解

既然和最小生成树有关,那么我们就先搞出一颗最小生成树。考虑一条非树边对在树上两点的路径上的树边有影响,他可以代替这条路径上的任何一条边如果权值满足。那么对于一条树边考虑一直增加它的权值,当权值达到那样一条可以代替它的非树边的权值时,就不能保证一定在最小生成树上了,所以我们得出:对于树边,k=min{能够代替它的非树边权值}-1。

对于非树边,考虑减少它的权值,当他到达一条他可以代替的树边的权值,他就可能在最小生成树上了,那么可以得出:对于非树边,k=max{路径上一条树边的权值}-1.

考虑维护信息,可以想到用树剖,维护非树边权值最小值mi和树边的最大值mx,建树时维护出mx,对于每条非树边都要对路径上的边的mi进行取min。

查询的话对于树边好像不用树剖,因为就是一条边,不过懒得改了。

#include<bits/stdc++.h>
using namespace std;

const int maxn=100005;
const int oo=1000000005;
int n,m,cnt;
int a[maxn],fa[maxn],size[maxn],dep[maxn],son[maxn];
int aa[maxn],top[maxn],id[maxn];
int root,ls[maxn<<1],rs[maxn<<1],mx[maxn<<1],mi[maxn<<1];//mx:最大树边权  mi:最小非树边权 
int tag[maxn<<1];//非树边 
vector<pair<int,int> >e[maxn];
bool used[maxn];
struct edge{
    int x,y,val,id;
}p[maxn],pp[maxn];

template<class T>inline void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

bool cmp(edge a,edge b){return a.val<b.val;}
int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}

void kruskal(){
    for(int i=1;i<=n;i++) fa[i]=i;
    int k=0;
    for(int i=1;i<=m;i++){
        int dx=find(pp[i].x),dy=find(pp[i].y);
        if(dx!=dy){
            k++;
            fa[dx]=dy;
            used[pp[i].id]=true;
            e[pp[i].x].push_back(make_pair(pp[i].y,pp[i].val));
            e[pp[i].y].push_back(make_pair(pp[i].x,pp[i].val));
            if(k==n-1) break;
        }
    }
    for(int i=1;i<=n;i++) fa[i]=0;
}

void dfs(int u){
    size[u]=1;
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        if(v==fa[u]) continue;
        dep[v]=dep[u]+1;
        fa[v]=u;
        a[v]=e[u][i].second;
        dfs(v);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}

void dfs(int u,int tp){
    top[u]=tp;
    id[u]=++cnt;
    aa[cnt]=a[u];
    if(!son[u]) return ;
    dfs(son[u],tp);
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        if(v==fa[u]||v==son[u]) continue;
        dfs(v,v);
    }
}

int min(int x,int y){return x<y ? x : y ;}
int max(int x,int y){return x>y ? x : y ;}

void update(int rt){
    mi[rt]=min(mi[ls[rt]],mi[rs[rt]]);
    mx[rt]=max(mx[ls[rt]],mx[rs[rt]]);
}

void build(int &rt,int l,int r){
    rt=++cnt;
    tag[rt]=oo;
    if(l==r){
        mi[rt]=oo;
        mx[rt]=aa[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(ls[rt],l,mid);
    build(rs[rt],mid+1,r);
    update(rt);
}

void put_tag(int rt,int val){
    mi[rt]=min(mi[rt],val);
    tag[rt]=min(tag[rt],val);
}

void push_down(int rt){
    put_tag(ls[rt],tag[rt]);
    put_tag(rs[rt],tag[rt]);
    tag[rt]=oo;
}

void modify(int rt,int l,int r,int a_l,int a_r,int val){
    if(a_l<=l&&r<=a_r) {
        put_tag(rt,val);
        return ;
    }
    if(tag[rt]!=oo) push_down(rt);
    int mid=(l+r)>>1;
    if(a_l<=mid) modify(ls[rt],l,mid,a_l,a_r,val);
    if(mid<a_r) modify(rs[rt],mid+1,r,a_l,a_r,val);
    update(rt);
}

void modify(int x,int y,int val){
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        modify(1,1,n,id[top[y]],id[y],val);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    modify(1,1,n,id[x]+1,id[y],val);
}

int querymin(int rt,int l,int r,int a_l,int a_r){
    if(a_l<=l&&r<=a_r) return mi[rt];
    if(tag[rt]!=oo) push_down(rt);
    int mid=(l+r)>>1;
    int ret=oo;
    if(a_l<=mid) ret=min(ret,querymin(ls[rt],l,mid,a_l,a_r));
    if(mid<a_r) ret=min(ret,querymin(rs[rt],mid+1,r,a_l,a_r));
    return ret;
}

int querymin(int x,int y){
    int ret=oo;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        ret=min(ret,querymin(1,1,n,id[top[y]],id[y]));
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ret=min(ret,querymin(1,1,n,id[x]+1,id[y]));
    return ret!=oo ? ret-1 : -1;
}

int querymax(int rt,int l,int r,int a_l,int a_r){
    if(a_l<=l&&r<=a_r) return mx[rt];
    int mid=(l+r)>>1;
    int ret=0;
    if(a_l<=mid) ret=max(ret,querymax(ls[rt],l,mid,a_l,a_r));
    if(mid<a_r) ret=max(ret,querymax(rs[rt],mid+1,r,a_l,a_r));
    return ret;
}

int querymax(int x,int y){
    int ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        ret=max(ret,querymax(1,1,n,id[top[y]],id[y]));
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ret=max(ret,querymax(1,1,n,id[x]+1,id[y]));
    return ret-1;
}

int main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=m;i++){
      read(p[i].x);read(p[i].y);read(p[i].val);
      pp[i]=(edge){p[i].x,p[i].y,p[i].val,i};
    }
    sort(pp+1,pp+m+1,cmp);
    kruskal();
    dfs(1);
    dfs(1,1);
    cnt=0;
    build(root,1,n);
    for(int i=1;i<=m;i++)
     if(!used[i])
         modify(p[i].x,p[i].y,p[i].val);
    for(int i=1;i<=m;i++){
        if(used[i]) printf("%d\n",querymin(p[i].x,p[i].y));
        else printf("%d\n",querymax(p[i].x,p[i].y));
    }
    return 0;
}
/*
4 4
2 1 2
3 2 2
4 3 2
1 4 3
*/
tree

猜你喜欢

转载自www.cnblogs.com/sto324/p/11420916.html