Codeforces Beta Round #88

做CF被血虐。。。下次要扳回來!


AB題就pass吧,現在直接切入正題(A掉AB題我都花了1個小時啊,混蛋。。)

C

給你一個競賽圖,要你找一個三元環。

solution

競賽圖的意思就是 Aij≠Aji ,一直都忘記用這個性質,悲催。。

下面講一個我翻別人代碼翻到的最優美的方法:

維護一個序列B,這個序列對於任意 i<j 滿足 A[B[i],B[j]]=1。

一開始序列爲空,然後把1到N一次插入這個序列,比如現在插入i號元素:

1.找到一個最小的L,滿足A[i,B[L]]=1;

2.找到一個最大的R,滿足A[i,B[R]]=0;

3.如果L=R+1,就吧i插入到L,R之間,如果L≠R,那麼我們就找到了一個環,因爲L<R,所以A[B[L],B[R]]=A[B[R],i]=A[i,B[L]]=1。

#include <vector>
#include <cstdio>
using namespace std;

char a[5010][5010];

int main() {
  int n,i;
  scanf("%d",&n);
  for (i=0;i<n;i++) scanf("%s",a[i]);
  vector<int> b(1,0);
  for (i=1;i<n;i++) {
    int l=0,r=i-1;
    while (l<i && a[i][b[l]]=='0') l++;
    while (r>=0 && a[i][b[r]]=='1') r--;
    if (l==r+1) b.insert(b.begin()+l,i);
           else {printf("%d %d %d\n",b[l]+1,b[r]+1,i+1);break;};
  };
  if (i==n) printf("-1\n");
  return 0;
}




D

題意有點複雜。。。

類似於線段樹,只不過不需要吧節點建出來。

每個節點的數一定是一個等差數列,所以只要在遞歸的過程中記下第一項就可以了。

#include <cstdio>
#include <algorithm>
using namespace std;

long long n,m,mo,l,r,u,v;

long long cal(long long a,long long b,long long c) {
  a-=b;
  if (a<0) a=-1; else a=a>>c;
  long long B=b+a*(1ll<<c);
  long long s;
  if ((++a)&1) s=((B+b)/2%mo)*(a%mo);
          else s=((B+b)%mo)*(a/2%mo);
  return s%mo;
}

long long cal(long long ll,long long rr,long long c,int d) {
  if (u>n) return 0;
  long long ans=0;
  if (l>ll || r<rr) {
    long long m=(ll+rr)>>1;
    if (l<=m) ans+=cal(ll,m,c,d+1);
    if (r>m) ans+=cal(m+1,rr,c+(1ll<<d),d+1);
    if (ans>=mo) ans-=mo;
  } else {
    ans=cal(v,c,d)-cal(u-1,c,d);
    if (ans<0) ans+=mo;
  };
  return ans;
}

int main() {
  scanf("%I64d%I64d%I64d",&n,&m,&mo);
  while (m--) {
    scanf("%I64d%I64d%I64d%I64d",&l,&r,&u,&v);
    v=min(v,n);
    long long ans=cal(1,n,1,0);
    printf("%I64d\n",ans%mo);
  };
  return 0;
}

E

給你一顆樹+一條邊,每條邊有01兩種狀態,要求支持兩種操作:

1.將從U到V的最短路上的邊的01狀態取反;

2.詢問只考慮狀態爲1的邊有多少個聯通快;


如果沒有那多出的一條邊的話,也就是要求詢問樹中有多少條狀態爲0的邊S,答案就是S+1;

加了一條邊也差不多,答案是S,不過要特殊考慮樹中的那一個環,如果這個環上的邊狀態全爲1的話還要把答案額外加一。

因此我們直接刪掉一條邊做動態樹就可以了。

第一次用C++寫動態樹,寫了2個多小時,oh NO。。

另外疑問就是爲什麼CF不能用memset?老是編譯錯誤?


#include <cstdio>
#include <algorithm>
#define N 100005
#define update(i) x[i]=x[l[i]]+x[r[i]]+a[i],y[i]=y[l[i]]+y[r[i]]+1-a[i];
using namespace std;

int t,T,L,mb,mdb,ans,d[N],z[N],g[N],o[N],fa[N],FA[N],p[N*2],next[N*2];

struct d_tree {
  int g,t,l[N],r[N],z[N],a[N],x[N],y[N],fa[N],root[N];
  void put(int i,int j) {if (i&&j) z[i]=!z[i],a[i]=!a[i],swap(x[i],y[i]);}
  void lazy(int i) {put(l[i],z[i]),put(r[i],z[i]),z[i]=0;}

  void rt(int i,int j) {
    if (l[i]==j) l[i]=r[j],fa[r[j]]=i,r[j]=i;
            else r[i]=l[j],fa[l[j]]=i,l[j]=i;
    root[j]=root[i],root[i]=0;
    if (l[fa[i]]==i) l[fa[i]]=j; else
    if (r[fa[i]]==i) r[fa[i]]=j;
    fa[j]=fa[i],fa[i]=j;
    update(i);update(j);
  }

  void splay(int i,int j) {
    if (root[i]) lazy(i);
    while (!root[i]) {
      lazy(fa[i]);
      lazy(i);
      rt(fa[i],i);
    };
    if (j) {
      root[g=r[i]]=1;
      r[i]=0;
      update(i);
    }
  }

  void access(int i) {
    splay(t=i,1);
    while (fa[i]) {
      splay(t=fa[i],1);
      r[t]=1,rt(t,i);
    };
  }

  void cover(int i) {
    access(i);
    splay(L,0);
    ans+=y[r[L]]-x[r[L]];
    put(r[L],1);
  }

} TREE;

void link(int a,int b) {next[++t]=d[a],d[a]=t,p[t]=b;}
int find(int i) {return (FA[i]==i)?i:FA[i]=find(FA[i]);}

void dfs(int i,int h) {
  z[++t]=i,o[i]=t;
  for (int k=d[i],j=p[k];k;k=next[k],j=p[k]) if ((h^k)!=1) {
    if (o[j]) {
      mb=k;
      for (int I=o[j];I<=t;I++) g[++T]=z[I];
    } else dfs(j,k);
  };
  t--;
}

void dfs2(int i,int h) {
  for (int k=d[i],j=p[k];k;k=next[k],j=p[k]) if ((h^k)!=1 && ((k^mb)>1)) {
    fa[j]=i;dfs2(j,k);
  };
}

int main() {
  int n,m,a,b,mdb=0;
  t=1;
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++) {
    scanf("%d%d",&a,&b);
    link(a,b);link(b,a);
  };
  t=0;
  dfs(1,0);
  dfs2(g[1],0);
  for (int i=0;i<N;i++) o[i]=0;
  for (int i=1;i<=T;i++) o[g[i]]=i;
  for (int i=1;i<=n;i++) FA[i]=(o[i])?i:fa[i];
  for (int i=1;i<=n;i++) find(i);
  for (int i=1;i<=n;i++) {
    TREE.fa[i]=fa[i];
    TREE.y[i]=TREE.root[i]=1;
  };
  g[0]=g[T],L=g[T+1]=g[1];
  while (m--) {
    scanf("%d%d",&a,&b);
    int Fa=FA[a],Fb=FA[b];
    int d1=abs(o[Fa]-o[Fb]);
    int g1,g2;
    if (o[Fa]<o[Fb]) g1=g[o[Fa]+1],g2=g[o[Fa]-1];
                else g1=g[o[Fa]-1],g2=g[o[Fa]+1];
    TREE.cover(a);
    TREE.cover(b);
    if (d1>T-d1 || ((d1==T-d1) && g1>g2)) {
      mdb=!mdb;
      if (mdb) ans++; else ans--;
      TREE.cover(g[T]);
    };
    TREE.access(g[T]);
    int al=TREE.x[g[T]]+mdb==T;
    printf("%d\n",n-ans+al);
  };
  return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章