2017.10.9离线赛总结

dbclick —2923

思路:一道很水的题目,随便怎么搞(向两边扩展或O(n)预处理)。然而我偏偏太过于自信,O(n)预处理时最后一个区域的R忘补充了(一敲起水题来就管不住这双手…)。

strsub —2991

思路:一道十分有趣的dp,虽然dp很明显,但需要找到其中的规律,结果是要前缀和维护前缀和…(欺负我读书少…)卡了我超久,最后只写了O(n^2),没有用hash优化(O(n))。

paths —2954

思路:简化题意,就是判两条路径是否相交。而假设两条路径相交,那么以任意一条的任意端点为根,交点一定是另一条路径的两个端点的lca。
此时,就冒出了一个神奇的贪心(正确性玄乎),将lca的深度从大到小排序,每个路径经过就mark掉。

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define N 100005
#define M 20
#define P 1000000007
#define INF 0x3f3f3f3f
#define LL long long
// LL mod 
using namespace std;
int n,m;
int fa[M][N],dis[N];
bool mark[N];
vector<int>E[N];
struct node{
    int f,dep,from,to;
    bool operator<(const node & a)const{
        return dep>a.dep;
    }
}Q[N];
//struct P_list{
//  int Ds,Dep,dep[N];
//  struct Node{
//      int L,R;
//      bool operator<(const Node &a)const{
//          return R<a.R;
//      } 
//  }es[N];
//  bool check(){
//      int sum=0;
//      REP(i,1,n)if(E[i].size()<2)Ds=i,sum++;
//      return sum==2;
//  }
//  void dfs(int x,int f,int d){
//      Dep=max(Dep,d);
//      dep[x]=d;
//      REP(i,0,E[x].size()-1){
//          int y=E[x][i];
//          if(y==f)continue;
//          dfs(y,x,d+1); 
//      }
//  }
//  void solve(){
//      Dep=0;
//      dfs(Ds,0,1);
        printf("Ds=%d Dep=%d\n",Ds,Dep);
//      REP(i,1,m)
//          es[i]=(Node){min(dep[Q[i].from],dep[Q[i].to]),max(dep[Q[i].from],dep[Q[i].to])};
//      sort(es+1,es+1+m);
//      int now=1,i=1,ans=0;
//      while(now<=Dep){
//          if(now<=es[i].L && es[i].R<=Dep)now=es[i].R,ans++;
//          i++;
//          if(i>m)break;
//      }
//      cout<<ans<<endl;
//  }
//
//
//}p_list;
struct P100{
    void dfs(int x,int f,int dep){
        fa[0][x]=f,dis[x]=dep;
        REP(i,0,E[x].size()-1){
            int y=E[x][i];
            if(y==f)continue;
            dfs(y,x,dep+1);
        }
    }
    void Up(int &x,int step){
        REP(i,0,M-1)if(step&(1<<i))x=fa[i][x];
    }
    int Lca(int a,int b){
        if(dis[a]>dis[b])swap(a,b);
        Up(b,dis[b]-dis[a]);
        if(a==b)return a;
        DREP(i,M-1,0)
            if(fa[i][a]!=fa[i][b])a=fa[i][a],b=fa[i][b];
        return fa[0][a];
    }
    void Dfs(int x,int f){
        if(mark[x])return;
        mark[x]=1;
        REP(i,0,E[x].size()-1){
            int y=E[x][i];
            if(y==f)continue;
            Dfs(y,x);
        }
    }
    void Init(){
        dfs(1,0,1);
        REP(j,1,M-1)
            REP(i,1,n)fa[j][i]=fa[j-1][fa[j-1][i]];
        REP(i,1,m){
            int lca=Lca(Q[i].from,Q[i].to);
            Q[i].f=lca,Q[i].dep=dis[lca];
        }
        sort(Q+1,Q+m+1);
    }
    void solve(){
        Init();
        int ans=0;
        REP(i,1,m){
            int f=Q[i].f,a=Q[i].from,b=Q[i].to;
            if(mark[f]||mark[a]||mark[b])continue;
            Dfs(f,fa[0][f]);
            ans++;
        }
        cout<<ans<<endl;
    }
}p100;
void Rd(){
    scanf("%d %d",&n,&m);
    REP(i,1,n-1){
        int a,b;
        scanf("%d%d",&a,&b);
        E[a].push_back(b);
        E[b].push_back(a);
    }
    REP(i,1,m)scanf("%d%d",&Q[i].from,&Q[i].to);
//  if(p_list.check())p_list.solve();
//  else p100.solve();
    p100.solve();
}
int main(){
    Rd();
    return 0;
}

小结:
最近几场考得很不稳定,忽高忽低地,每次不是第1题没ac就是第2题暴力打错了,第3题不用说了,没爆0就可以了…
这说明这自己的思维很不严谨呀!确实,第1、2题经常是没对拍的,或者说有时候连暴力都不好写…这又体现自己的dfs、全排列还不行呀。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值