day2018.8.24模拟赛总结

版权声明:转载请注明原出处啦(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/82015652

T1

题目大意:大概就是在一张无向图(不一定连通)上,删掉一些边,使得这一张图没有一个边双连通分量.

这道题考场上的时候是想这直接把边双求出来,然后每一个边双的最小生成树求出来就好了.

但是正解只需要写一个最小生成树就可以了,我是不是太菜了,没想到...

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
#define js(x1,y1,x2,y2) sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
typedef long long LL;
const int N=10000;
const int M=50000;
struct side{
  int x,y,next;
  double v;
  bool flag;
}e[M*2+9];
int n,m,top=1,num,dfn[N+9],low[N+9],c[N+9],dcc,lin[N+9],fa[N+9];
double x[N+9],y[N+9],sum,ma;
Abigail ins(int X,int Y,double V){
  e[++top].x=X;e[top].y=Y;e[top].v=V;
  e[top].next=lin[X];
  lin[X]=top;
}
void tarjan(int x,int inedge){
  dfn[x]=low[x]=++num;
  for (int i=lin[x];i;i=e[i].next)
    if (!dfn[e[i].y]){
      tarjan(e[i].y,i);
      low[x]=min(low[x],low[e[i].y]);
      if (low[e[i].y]>dfn[x])
        e[i].flag=e[i^1].flag=1;
    }else if (i^(inedge^1)) low[x]=min(low[x],dfn[e[i].y]);
}
void dfs(int x){
  c[x]=dcc;
  for (int i=lin[x];i;i=e[i].next){
    if (c[e[i].y]||e[i].flag) continue;
    dfs(e[i].y);
  }
}
inline bool cmp(side a,side b){
  return a.v>b.v;
}
int get(int u){
  if (u^fa[u]) return fa[u]=get(fa[u]);
  else return u;
}
Abigail kruskal(){
  sort(e+2,e+top+2,cmp);
  for (int i=1;i<=n;i++) fa[i]=i;
  for (int i=2;i<=top;i++)
    if (get(e[i].x)^get(e[i].y)&&c[e[i].x]==c[e[i].y]&&!e[i].flag){
      ma+=e[i].v;
      fa[get(e[i].y)]=get(e[i].x);
    }
}
Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++)
    scanf("%lf%lf",&x[i],&y[i]);
  int u,v;
  double g;
  for (int i=1;i<=m;i++){
    scanf("%d%d",&u,&v);
    g=js(x[u],y[u],x[v],y[v]);
    ins(u,v,g);ins(v,u,g);
  }
}
Abigail work(){
  for (int i=1;i<=n;i++)
    if (!dfn[i]) tarjan(i,0);
  for (int i=1;i<=n;i++)
    if (!c[i]){
      ++dcc;dfs(i);
    }
  for (int i=2;i<top;i+=2)
    if (!e[i].flag) sum+=e[i].v;
  kruskal();
}
Abigail outo(){
  printf("%.9lf\n",sum-ma);
}
int main(){
  freopen("plan.in","r",stdin);
  freopen("plan.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}

T2

题目大意:A和B玩下棋,棋盘是1*n的,他们之中先手先在第1~m格放一颗棋子,然后之后的人就得在上一个人之后的1~m格选一格放棋子,并且放到的格子就可以获得这个格子的分数A[i].现在他们想知道,当两人都选择最优策略(让差最大)的时候,差是多少.

这道题我一开始在想极大极小搜索写暴力,然后我就想到了可以写逆推DP,用f[i][0]表示当前第i格是A在下棋A-B的差,f[i][1]是B在这格.

然后我推出了方程:

f[i][0]=max_{i<j\leq min(i+m,n)}(f[i+j][1])+a[i]

f[i][1]=min_{i<j\leq min(i+m,n)}(f[i+j][0])-a[i]

然后我又用线段树来维护这个东西,理论上可以过了.

不过我考场爆0了,因为我把逆推的循环写成了顺推...

考场爆0代码:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct tree{
  int l,r;
  LL min,max;
}tr[N*5][2];
LL a[N+9];
int n,m;
Abigail pushup(int k,int t){
  int ls=k<<1,rs=k<<1|1;
  tr[k][t].min=min(tr[ls][t].min,tr[rs][t].min);
  tr[k][t].max=max(tr[ls][t].max,tr[rs][t].max);
}
void build(int L,int R,int t,int k=1){
  tr[k][t].l=L;tr[k][t].r=R;
  if (L==R)return;
  int mid=L+R>>1;
  build(L,mid,t,k<<1);build(mid+1,R,t,k<<1|1);
}
void change(int x,LL num,int t,int k=1){
  if (tr[k][t].l==tr[k][t].r){
    tr[k][t].max=tr[k][t].min=num;
    return;
  }
  int mid=tr[k][t].l+tr[k][t].r>>1;
  if (x<=mid) change(x,num,t,k<<1);
  else change(x,num,t,k<<1|1);
  pushup(k,t);
}
LL query_max(int L,int R,int t,int k=1){
  if (L==tr[k][t].l&&R==tr[k][t].r) return tr[k][t].max;
  int mid=tr[k][t].l+tr[k][t].r>>1;
  if (R<=mid) return query_max(L,R,t,k<<1);
  else if (L>mid) return query_max(L,R,t,k<<1|1);
    else return max(query_max(L,mid,t,k<<1),query_max(mid+1,R,t,k<<1|1)); 
}
LL query_min(int L,int R,int t,int k=1){
  if (L==tr[k][t].l&&R==tr[k][t].r) return tr[k][t].min;
  int mid=tr[k][t].l+tr[k][t].r>>1;
  if (R<=mid) return query_min(L,R,t,k<<1);
  else if (L>mid) return query_min(L,R,t,k<<1|1);
    else return max(query_min(L,mid,t,k<<1),query_min(mid+1,R,t,k<<1|1)); 
}
Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
}
Abigail work(){
  build(1,n,0);build(1,n,1);
  change(n,a[n],0);change(n,-a[n],1);
  for (int i=1;i<n;i++){
    change(i,query_max(i+1,min(n,i+m),1),0);
    change(i,query_min(i+1,min(n,i+m),0),1);
  }
}
Abigail outo(){
  printf("%lld\n%lld\n",query_max(1,min(n,m),0),query_min(1,min(n,m),1));
}
int main(){
  freopen("game.in","r",stdin);
  freopen("game.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}

然后我进行了一通魔改之后代码就变成了单调队列,AC代码:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct Now{
  int id;
  LL num;
}q0[N+9],q1[N+9];
int n,m,h0,h1,t0,t1;
LL a[N+9],f[N+9][2];      //我把0和1换一下应该没事>_< 
Abigail push0(LL num,int id){
  while (h0<=t0&&q0[t0].num>=num) --t0;
  q0[++t0].num=num;q0[t0].id=id;
}
Abigail push1(LL num,int id){
  while (h1<=t1&&q1[t1].num<=num) --t1;
  q1[++t1].num=num;q1[t1].id=id;
}
Abigail pop0(int id){
  while (q0[h0].id>=id) ++h0;
}
Abigail pop1(int id){
  while (q1[h1].id>=id) ++h1;
}
LL front0(){
  return q0[h0].num;
}
LL front1(){
  return q1[h1].num;
}
Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
}
Abigail work(){
  h0=h1=0;t0=t1=-1;
  push0(-a[n],n);
  push1(+a[n],n);
  for (int i=n-1;i>=0;i--){
    f[i][0]=front1();
    f[i][1]=front0();
    pop0(i+m);pop1(i+m);
    push0(f[i][0]-a[i],i);
    push1(f[i][1]+a[i],i);
  }
}
Abigail outo(){
  printf("%lld\n%lld\n",f[0][0],f[0][1]);
}
int main(){
  freopen("game.in","r",stdin);
  freopen("game.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}

T3

题目大意:维护树在没有两棵子树x和y时候的直径,边权一定是1.

啊我的两遍bfs求树的直径写挂了...

这道题我们可以考虑使用线段树维护dfs序来做.

我们考虑维护每一个区间的直径ans和直径两端u和v,当这点u和v不在这个区间中的同一个连通块(或者说lca不在这个区间内)的时候我们不用慌,因为我们最后找的时候绝对是一棵子树,所以绝对是在一个区间里的.

合并的时候我们考虑将直径设成四个点的最远点对.

证明:

我们考虑若直径不用跨越两个区间,则直径就是两条直径取max.

而若要跨越,显然,新直径的两个端点一定是旧直径的端点.

证毕.

那么如何找最远点对?LCA就可以了.

代码如下(这代码太难调了,重新对着dalao的代码写了一遍):

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100009;
struct TR{
  int x,y,len;
  TR(int X=0,int Y=0,int z=0){x=X;y=Y;len=z;}
};
TR tr[N*4];
struct side{
  int y,next;
}e[N*2];
int top,lin[N],n,q,fa[N*2][20],de[N],ap[N*2],fir[N*2],Log[2*N],er[20];
void ins(int X,int Y){
  e[++top].y=Y;
  e[top].next=lin[X];
  lin[X]=top;
}
void start(){
  for (int i=1;i<=ap[0];i++)
    fa[i][0]=ap[i],Log[i]=log(i)/log(2);
  for (int i=0;i<=19;i++) er[i]=1<<i;
  for (int j=1;j<=19;j++)
    for (int i=1;i<=ap[0];i++){
      fa[i][j]=fa[i][j-1];
      if (i+er[j-1]<=ap[0]&&de[fa[i+er[j-1]][j-1]]<de[fa[i][j]])
        fa[i][j]=fa[i+er[j-1]][j-1];
    }
}
int lca(int x,int y){
  x=fir[x];y=fir[y];
  if (x>y) swap(x,y);
  int t=Log[y-x+1];
  if (de[fa[x][t]]<de[fa[y-er[t]+1][t]]) return fa[x][t];
  else return fa[y-er[t]+1][t];
}
int st[N],en[N],sum,Tbh[N];
void dfs(int k,int fa){
  de[k]=de[fa]+1;
  ap[++ap[0]]=k;fir[k]=ap[0];
  Tbh[++sum]=k;st[k]=sum;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^fa){
      dfs(e[i].y,k);
      ap[++ap[0]]=k;
    }
  en[k]=sum;
}
int dis(int x,int y){
  return de[x]+de[y]-de[lca(x,y)]*2;
}
TR merge(TR a,TR b){
  if (a.len==-1) return b;
  TR c;
  if (a.len>b.len) c=a;
  else c=b;
  if (dis(a.x,b.x)>c.len) c=TR(a.x,b.x,dis(a.x,b.x));
  if (dis(a.x,b.y)>c.len) c=TR(a.x,b.y,dis(a.x,b.y));
  if (dis(a.y,b.x)>c.len) c=TR(a.y,b.x,dis(a.y,b.x));
  if (dis(a.y,b.y)>c.len) c=TR(a.y,b.y,dis(a.y,b.y));
  return c;
}
void build(int L,int R,int k=1){
  if (L==R){
    tr[k].x=tr[k].y=Tbh[L];
    tr[k].len=0;
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1),build(mid+1,R,k<<1|1);
  tr[k]=merge(tr[k<<1],tr[k<<1|1]);
}
TR query(int L,int R,int l=1,int r=n,int k=1){
  if (L==l&&R==r) return tr[k];
  int mid=l+r>>1;
  if (R<=mid) return query(L,R,l,mid,k<<1);
  else if (L>mid) return query(L,R,mid+1,r,k<<1|1);
    else return merge(query(L,mid,l,mid,k<<1),query(mid+1,R,mid+1,r,k<<1|1));
}
Abigail into(){
  scanf("%d%d",&n,&q);
  for (int i=1;i<n;i++){
    int x,y;
    scanf("%d%d",&x,&y);
    ins(x,y);ins(y,x);
  }
}
Abigail work(){
  dfs(1,0);
  start();
  build(1,n);
  for (int i=1;i<=q;i++){
    int x,y;
    scanf("%d%d",&x,&y);
    if (st[x]>st[y]) swap(x,y);
    TR ans=TR(0,0,-1);
    if (1<st[x]) ans=merge(ans,query(1,st[x]-1));
    if (en[x]+1<st[y]) ans=merge(ans,query(en[x]+1,st[y]-1));
    int En=max(en[x],en[y]);
    if (En<n) ans=merge(ans,query(En+1,n));
    printf("%d\n",(ans.len==-1)?0:ans.len);
  }
}
Abigail outo(){
}
int main(){
  freopen("find.in","r",stdin);
  freopen("find.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/82015652
今日推荐