9.10 模拟赛

模拟赛第二弹,这次做的好多了~

T1 

题意就是给一棵树,求点对之间的距离

因为n非常小(<1000),所以直接暴力bfs.....

然而我为了锻炼手速 其实是没看数据 打了树剖【雾】

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 struct edge{
  7     int to,w,next;
  8 }e[2010];
  9 int n,q,times=1,first[1010],fa[1010],son[1010],size[1010],dep[1010];
 10 int wei[1010],belong[1010],pos[510][1010],lian[1010],top[1010];
 11 int a[1010][8010],nb[510],len[1010];
 12 bool vis[1010];
 13 void dfs1(int k,int f,int weight){
 14     int i,u,maxn=0,tmp=0;
 15     fa[k]=f;vis[k]=1;dep[k]=dep[f]+1;size[k]=1;
 16     len[k]=weight;
 17     for(i=first[k];~i;i=e[i].next){
 18         u=e[i].to;
 19         if(!vis[u]){
 20             dfs1(u,k,e[i].w);
 21             size[k]+=size[u];
 22             if(size[u]>maxn){
 23                 maxn=size[u];tmp=u;
 24             }
 25         }
 26     }
 27     son[k]=tmp;
 28     return;
 29 }
 30 void dfs2(int k,int t,int cnt){
 31     int i,u;nb[times]++;
 32     belong[k]=times;pos[times][cnt]=k;wei[k]=cnt;lian[k]=lian[fa[t]]+1;
 33     vis[k]=1;top[k]=t;
 34     if(son[k]){
 35         dfs2(son[k],t,cnt+1);
 36     }
 37     for(i=first[k];~i;i=e[i].next){
 38         u=e[i].to;
 39         if(!vis[u]){
 40             ++times;
 41             dfs2(u,u,1);
 42         }
 43     }
 44 }
 45 void build(int l,int r,int num,int t){
 46     if(l==r){
 47         a[t][num]=len[pos[t][l]];return;
 48     }
 49     int mid=(l+r)>>1;
 50     build(l,mid,num<<1,t);build(mid+1,r,(num<<1)+1,t);
 51     a[t][num]=a[t][num<<1]+a[t][(num<<1)+1];
 52     return;
 53 }
 54 int find(int ql,int qr,int l,int r,int num,int t){
 55     if(qr<l||ql>r) return 0;
 56     if(l>=ql&&r<=qr) return a[t][num];
 57     int mid=(l+r)>>1,re=0;
 58     if(mid>=ql) re+=find(ql,qr,l,mid,num<<1,t);
 59     if(mid<qr) re+=find(ql,qr,mid+1,r,(num<<1)+1,t);
 60     return re;
 61 }
 62 void swap(int &x,int &y){
 63     x^=y;y^=x;x^=y;
 64 }
 65 int query(int l,int r){
 66     int re=0;
 67     if(lian[l]>lian[r]) swap(l,r);
 68     while(lian[r]!=lian[l]){
 69         re+=find(wei[top[r]],wei[r],1,nb[belong[r]],1,belong[r]);
 70         r=fa[top[r]];
 71     }
 72     while(top[l]!=top[r]){
 73         re+=find(wei[top[l]],wei[l],1,nb[belong[l]],1,belong[l]);
 74         l=fa[top[l]];
 75         re+=find(wei[top[r]],wei[r],1,nb[belong[r]],1,belong[r]);
 76         r=fa[top[r]];
 77     }
 78     if(l==r) return re;
 79     if(dep[l]>dep[r]) swap(l,r);
 80     return re+find(wei[l],wei[r],1,nb[belong[l]],1,belong[l])-len[l];
 81 }
 82 int main(){
 83     freopen("pwalk.in","r",stdin);
 84     freopen("pwalk.out","w",stdout);
 85     int i,t1,t2,t3;
 86     memset(first,-1,sizeof(first));
 87     scanf("%d%d",&n,&q);
 88     for(i=1;i<n;i++){
 89         scanf("%d%d%d",&t1,&t2,&t3);
 90         e[i*2-1].to=t2;e[i*2-1].w=t3;e[i*2-1].next=first[t1];first[t1]=i*2-1;
 91         e[i*2].to=t1;e[i*2].w=t3;e[i*2].next=first[t2];first[t2]=i*2;
 92     }
 93     memset(vis,0,sizeof(vis));
 94     dfs1(1,1,0);
 95     memset(vis,0,sizeof(vis));
 96     dfs2(1,1,1);
 97     for(i=1;i<=times;i++) build(1,nb[i],1,i);
 98     for(i=1;i<=q;i++){
 99         scanf("%d%d",&t1,&t2);
100         printf("%d
",query(t1,t2));
101     }
102 }

T2

题意:有一个n*m的池子,每个格子有四种状态:0水面,1石头,2荷叶,3荷叶并且是出发点,4荷叶并且是目的地

每次能跳一个“日”字,问在放最少的荷叶且的情况下有多少种放置方法

思路:bfs,对于每个点标记f[i][j]为最少放置的荷叶数,num[i][j]为总步数,然后bfs,根据先 f 再更新um 的方法。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #define inf 0x7fffffff
 9 #define ll long long
10 using namespace std;
11 inline int read()
12 {
13     int x=0,f=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 struct node{
19     int add,num,in;
20 }a[50][50];
21 const int dx[9]={0,1,1,-1,-1,2,2,-2,-2},dy[9]={0,2,-2,2,-2,1,-1,1,-1};
22 int n,m,opx,opy,edx,edy;
23 bool vis[50][50];
24 void bfs(){
25     queue<pair<int,int> >q;vis[opx][opy]=1;
26     pair<int,int>t;
27     t.first=opx;t.second=opy;
28     q.push(t);
29     int x,y,tx,ty,i,tmp;
30     while(!q.empty()){
31         t=q.front();q.pop();
32         x=t.first;y=t.second;vis[x][y]=0;
33 //        cout<<"bfs in "<<x<<ends<<y<<endl;
34         for(i=1;i<=8;i++){
35             tx=x+dx[i];ty=y+dy[i];
36             if(tx>0&&tx<=n&&ty>0&&ty<=m&&a[tx][ty].in!=2){
37                 tmp=(a[tx][ty].in==0);
38                 t.first=tx;t.second=ty;
39                 if(a[x][y].add+tmp<a[tx][ty].add){
40 //                    cout<<"    type 1: going to "<<tx<<ends<<ty<<endl;
41                     a[tx][ty].add=a[x][y].add+tmp;
42                     a[tx][ty].num=a[x][y].num;
43                     if(!vis[tx][ty]){
44                         q.push(t);vis[tx][ty]=1;
45                     }
46                     continue;
47                 }
48                 if(a[x][y].add+tmp==a[tx][ty].add){
49 //                    cout<<"    type 2: going to "<<tx<<ends<<ty<<endl;
50                     a[tx][ty].num+=a[x][y].num;
51                     if(!vis[tx][ty]){
52                         q.push(t);vis[tx][ty]=1;
53                     }
54                     continue;
55                 }
56             }
57         }
58     }
59 }
60 int main(){
61     int i,j;
62     n=read();m=read();
63     for(i=1;i<=n;i++){
64         for(j=1;j<=m;j++){
65             a[i][j].in=read();
66             a[i][j].add=inf;
67             if(a[i][j].in==3){
68                 opx=i;opy=j;
69                 a[i][j].add=0;a[i][j].num=1;
70             }
71             if(a[i][j].in==4){
72                 edx=i;edy=j;
73             }
74         }
75     }
76     bfs();
77     if(a[edx][edy].add==inf) printf("-1");
78     else printf("%d
%d",a[edx][edy].add,a[edx][edy].num);
79 }
80 /*
81 
82 4 5
83 1 0 0 0 0
84 3 0 0 0 0
85 0 0 2 0 0
86 0 0 0 4 0
87 
88 */

T3:

题意:有n个房间,q组询问,对于每一组询问,可能是入驻连续x个人,如果没有连续x个空房就跳过,也有可能是退一批房间(退掉的有可能是空的房间)

一开始全是空房,对于每一个合理的入驻请求,输出连续x个房间中编号最小的那一个

题解:看到连续房间和询问立马想到了线段树......然而比赛的时候似乎时间不够写挂了

正解是用left,right和maxn标记每一个区间的左起连续空房、右起连续空房和最大空房数,每一次维护lazy的时候回溯处理加一步更新就好了

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 struct node{
 7     int l,r,x,y,len,lazy;
 8     node(){
 9         l=r=lazy=len=0;
10     }
11 }a[200100];
12 void build(int l,int r,int num){
13     a[num].l=l;a[num].r=r;
14     a[num].x=a[num].y=a[num].len=r-l+1;
15     int mid=(l+r)>>1;
16     if(l!=r){
17         build(l,mid,num<<1);build(mid+1,r,(num<<1)+1);
18     }
19 }
20 void clear(int num){
21     if(a[num].l==a[num].r||!a[num].lazy) return;
22     int son=num<<1;
23     if(a[num].lazy==2){
24         a[son].x=a[son].y=a[son].len=a[son].r-a[son].l+1;
25         a[son+1].x=a[son+1].y=a[son+1].len=a[son+1].r-a[son+1].l+1;
26         a[son].lazy=a[son+1].lazy=1;
27     }
28     else{
29         a[son].x=a[son].y=a[son].len=0;
30         a[son+1].x=a[son+1].y=a[son+1].len=0;
31         a[son].lazy=a[son+1].lazy=2;
32     }
33     a[num].lazy=0;
34 }
35 int find(int len,int num){
36 //    cout<<"find "<<len<<ends<<num<<endl;
37     int son=num<<1;
38     clear(num);clear(son);clear(son+1);
39     if(a[num].x>=len) return a[num].l;
40     if(a[son].len>=len) return find(len,son);
41     if(a[son].y+a[son+1].x>=len) return a[son].r-a[son].y+1;
42     return find(len,son+1);
43 }
44 void update(int num){
45 //    cout<<"update "<<num<<endl;
46     int son=num<<1;
47     clear(son);clear(son+1);
48     a[num].x=((a[son].len==a[son].r-a[son].l+1)?a[son].x+a[son+1].x:a[son].x);
49     a[num].y=((a[son+1].len==a[son+1].r-a[son+1].l+1)?a[son+1].y+a[son].y:a[son+1].y);
50 //    cout<<a[num].len<<endl;
51     a[num].len=max(a[son].len,a[son+1].len);
52 //    cout<<a[num].len<<endl;
53     a[num].len=max(a[num].len,a[son].y+a[son+1].x);
54 //    cout<<a[num].len<<endl;
55 }
56 void checkin(int l,int r,int num){
57     clear(num);
58     if(a[num].l>r||a[num].r<l) return;
59     if(a[num].l>=l&&a[num].r<=r){
60         a[num].x=a[num].y=a[num].len=0;a[num].lazy=1;return;
61     }
62     int mid=(a[num].l+a[num].r)>>1,son=num<<1;
63     if(mid>=l) checkin(l,r,son);
64     if(mid<r) checkin(l,r,son+1);
65     update(num);
66 }
67 void checkout(int l,int r,int num){
68     clear(num);
69     if(a[num].l>r||a[num].r<l) return;
70     if(a[num].l>=l&&a[num].r<=r){
71         a[num].x=a[num].y=a[num].len=a[num].r-a[num].l+1;a[num].lazy=2;return;
72     }
73     int mid=(a[num].l+a[num].r)>>1,son=num<<1;
74     if(mid>=l) checkout(l,r,son);
75     if(mid<r) checkout(l,r,son+1);
76     update(num);
77 }
78 int n,m,ans;
79 int main(){
80     int i,t1,t2,t3;
81     scanf("%d%d",&n,&m);
82     build(1,n,1);
83     for(i=1;i<=m;i++){
84         scanf("%d",&t1);
85         if(t1==1){
86             scanf("%d",&t2);
87             if(a[1].len<t2){
88                 printf("0
");continue;
89             }
90             ans=find(t2,1);
91             printf("%d
",ans);
92             checkin(ans,ans+t2-1,1);
93         }
94         else{
95             scanf("%d%d",&t2,&t3);
96             checkout(t2,t2+t3-1,1);
97         }
98     }
99 }

T4:

题意:有一个图求最小生成树,使得从某一个点出发,对于路上每经过一次的点加一次该点权值,通过的边也加一次权值,问怎样最小,输出最小值

思路:kruskal,因为对于任何一个点来说,他有多少条出边就会加多少次该点的权值。

因此输入的时候把每条边加上两端端点的权值,跑kruskal,最后再加上一个点权最小的点就好了(因为根据题意这个点多跑一遍)

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace std;
 6 struct erickin{
 7     int to,next,from,w;
 8 }a[200100];
 9 int n,m,wei[10010],first[10010];
10 ll ans=0;
11 int f[10010];
12 bool cmp(erickin l,erickin r){
13     return l.w<r.w;
14 }
15 int find(int k){
16     return ((f[k]==k)?k:f[k]=find(f[k]));
17 }
18 void kruskal(){
19     int i,times=0,fx,fy;
20     for(i=1;i<=n;i++) f[i]=i;
21     for(i=1;i<=m;i++){
22         fx=find(a[i].from);fy=find(a[i].to);
23         if(fx!=fy){
24             f[fx]=fy;ans+=a[i].w;
25             times++;
26             if(times==n-1) break;
27         }
28     }
29 }
30 int main(){
31     int i,t1,t2,t3;
32     scanf("%d%d",&n,&m);
33     for(i=1;i<=n;i++) scanf("%d",&wei[i]);
34     for(i=1;i<=m;i++){
35         scanf("%d%d%d",&t1,&t2,&t3);
36         a[i].to=t2;a[i].from=t1;a[i].next=first[t1];first[t1]=i;a[i].w=t3*2+wei[t1]+wei[t2];
37     }
38 //    for(i=1;i<=m;i++) cout<<a[i].from<<ends<<a[i].to<<ends<<a[i].w<<endl;
39     sort(a+1,a+m+1,cmp);
40     sort(wei+1,wei+n+1);
41     kruskal();
42     printf("%lld",ans+wei[1]);
43 }
44 /*
45 5 7
46 10
47 10
48 20
49 6
50 30
51 1 2 5
52 2 3 5
53 2 4 12
54 3 4 17
55 2 5 15
56 3 5 6
57 4 5 12
58 */
原文地址:https://www.cnblogs.com/dedicatus545/p/7530657.html